From 725c0ed0a5aa3ee68b8e8bd7bf93586b937894e2 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 08:11:03 +0100 Subject: [PATCH 001/327] build(deps): bump FsCheck from 2.14.3 to 2.14.4 in /exercises (#1484) Bumps [FsCheck](https://github.com/fsharp/FsCheck) from 2.14.3 to 2.14.4. - [Release notes](https://github.com/fsharp/FsCheck/releases) - [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md) - [Commits](https://github.com/fsharp/FsCheck/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> --- exercises/diamond/Diamond.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/diamond/Diamond.csproj b/exercises/diamond/Diamond.csproj index b507b38504..9c1f0ef085 100644 --- a/exercises/diamond/Diamond.csproj +++ b/exercises/diamond/Diamond.csproj @@ -9,7 +9,7 @@ - + From b8d19a919324f05d5ae9032428e9f854bcd4ca40 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Tue, 2 Feb 2021 08:12:00 +0100 Subject: [PATCH 002/327] build(deps): bump FsCheck.Xunit from 2.14.3 to 2.14.4 in /exercises (#1483) Bumps [FsCheck.Xunit](https://github.com/fsharp/FsCheck) from 2.14.3 to 2.14.4. - [Release notes](https://github.com/fsharp/FsCheck/releases) - [Changelog](https://github.com/fscheck/FsCheck/blob/master/FsCheck%20Release%20Notes.md) - [Commits](https://github.com/fsharp/FsCheck/commits) Signed-off-by: dependabot-preview[bot] Co-authored-by: dependabot-preview[bot] <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: Erik Schierboom --- exercises/diamond/Diamond.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/diamond/Diamond.csproj b/exercises/diamond/Diamond.csproj index 9c1f0ef085..a9ce1b45ea 100644 --- a/exercises/diamond/Diamond.csproj +++ b/exercises/diamond/Diamond.csproj @@ -10,7 +10,7 @@ - + From 7488cdf84a2fcf65a4506a2180361fe8a8fc2fae Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Tue, 14 Jan 2020 14:02:12 +0000 Subject: [PATCH 003/327] Giant reshuffle * Rearrange * Set theme jekyll-theme-architect * Add nav * Move layout to the correct place * Change theme * Add docsify generated site * Rename link * Add extra sidebar * Fix sidebars * Fix C readme link * Rearrange repo * Add some basic docs * Fixing broken links * Update docs/concept-exercises.md Co-Authored-By: Erik Schierboom * Update docs/concept-exercises.md Co-Authored-By: Erik Schierboom * Update docs/concept-exercises.md Co-Authored-By: Erik Schierboom * Fix sidebars * Updated links * Add maintainers info * Add tooling sidebar * Fix more broken links * Add extra start to get started * Additional link-fixes * Additional link-fixes * Rename content to reference * Update repository structure * Move exercise-shared files to separate section * update to new structure * create docs, reference and exercises directory * make README and index * renamed concept-exercises to reference * move cli.md and debug.md to exercise/.docs directory * add how to implement document * update links * add concept-exercises document * add concept exercises * fix invalid escaping * fix link * add todo for converting to Fact-based tests * add shared file * add new concept exercise template * add reference to how to implement * fix grammar * replace duplicate information * Fix broken links * Add link to C# reference * add example for new concept exercise * example of reference * add contributing * add link * update links * add sidebar * update sidebar * more work * Tweak README * update README * add contributing information for reference documents * Add license * Add GitHub information to repository structure * Add subdivision for exercises directory in repository structure * Update language contributing text * Update languages/README.md Co-Authored-By: Jeremy Walker * Update languages/README.md Co-Authored-By: Jeremy Walker * add document for contributing to exercise-shared documents * templates: make implement new concept exercise template generic * Fix about * add suggest new exercise template * Add new concept exercise info * templates: add placeholder brackets * Add ask a question template * Update ask question template * Update markdown * Update contributing * update name * Update documents * Add links to all reference documents * Add links to implemented files * Add link to reference docs contributing * Improve links * Update links * remove dependencies * add more contributing * add readme for docs * Add links to analyzer/representer/test-runner * update strings * bitwise operations to fact-base * add defaults * convert tests to fact-based * add sidebars * add link * Change V3 to v3 * Consistent casing * change order * Update README * Update README.md * Tweak things further * More tweaks * Fix links * Fix typos * Change * rework readme * updates * update readme * update word * update * move concepts * Add reference doc * Fix template links * more work * Simplify * remove unused link * remove empty row * removing contributing * explain * Update README.md * Update README.md * Update README.md * Add maintainers docs * Add links * Update C# readme * Fix link * Fix link * Tweak repo structure document * Small improvements * fixes * more * Fix typo * Add converting details * structure: make it more clear * Add new README and docs * Split out readiness steps further * Split out online editor settings further * Tweak the repo structure docs a little * Tweak the README for clarity * Add new language docs * link directly to analyzer and representer * move concept interpretation to reference doc * small update * add online editor settings * add config.json example * more data * Use consistent example * Add online editor config changes * Update README.md Co-Authored-By: Erik Schierboom * Update README.md Co-Authored-By: Erik Schierboom * Update docs/_sidebar.md Co-Authored-By: Erik Schierboom * Update docs/_sidebar.md Co-Authored-By: Erik Schierboom * Update docs/concept-exercises.md Co-Authored-By: Erik Schierboom * Update docs/concept-exercises.md * Update docs/maintainers/README.md Co-Authored-By: Erik Schierboom * Apply suggestions from code review Co-Authored-By: Erik Schierboom * Apply suggestions from code review Co-Authored-By: Erik Schierboom * Update languages/docs/examples/new-concept-exercise-arrays.md Co-Authored-By: Jeremy Walker * Update languages/docs/examples/new-concept-exercise-arrays.md Co-Authored-By: Jeremy Walker * Move migrating config json file to separate file * Add more details * Add introduction for what maintainers actually need to do * Update README.md * Move things around for clarity * Fix tons of issues * Fix links * Fix links * More fixes * Fix things more * Revert link * Rephrase * Add maintainers * update * casing Co-authored-by: Charles Care Co-authored-by: Erik Schierboom --- .../concept/bitwise-operations/.docs/after.md | 5 + .../concept/bitwise-operations/.docs/hints.md | 21 +++ .../bitwise-operations/.docs/instructions.md | 55 +++++++ .../bitwise-operations/.docs/introduction.md | 3 + .../bitwise-operations/.meta/Example.cs | 39 +++++ .../bitwise-operations/.meta/config.json | 94 ++++++++++++ .../bitwise-operations/BitwiseOperations.cs | 28 ++++ .../BitwiseOperations.csproj | 13 ++ .../BitwiseOperationsTest.cs | 92 +++++++++++ exercises/concept/dates/.docs/after.md | 5 + exercises/concept/dates/.docs/hints.md | 29 ++++ exercises/concept/dates/.docs/instructions.md | 48 ++++++ exercises/concept/dates/.docs/introduction.md | 7 + exercises/concept/dates/.meta/Example.cs | 16 ++ exercises/concept/dates/.meta/config.json | 102 ++++++++++++ exercises/concept/dates/Dates.cs | 24 +++ exercises/concept/dates/Dates.csproj | 13 ++ exercises/concept/dates/DatesTest.cs | 145 ++++++++++++++++++ exercises/concept/enums/.docs/hints.md | 23 +++ exercises/concept/enums/.docs/instructions.md | 55 +++++++ exercises/concept/enums/.docs/introduction.md | 3 + exercises/concept/enums/.meta/Example.cs | 21 +++ exercises/concept/enums/.meta/config.json | 38 +++++ exercises/concept/enums/Enums.cs | 16 ++ exercises/concept/enums/Enums.csproj | 13 ++ exercises/concept/enums/EnumsTest.cs | 36 +++++ .../numbers-floating-point/.docs/after.md | 15 ++ .../numbers-floating-point/.docs/hints.md | 22 +++ .../.docs/instructions.md | 45 ++++++ .../.docs/introduction.md | 13 ++ .../numbers-floating-point/.meta/Example.cs | 41 +++++ .../numbers-floating-point/.meta/config.json | 102 ++++++++++++ .../NumbersFloatingPoint.cs | 19 +++ .../NumbersFloatingPoint.csproj | 13 ++ .../NumbersFloatingPointTest.cs | 100 ++++++++++++ exercises/concept/numbers/.docs/hints.md | 20 +++ .../concept/numbers/.docs/instructions.md | 34 ++++ .../concept/numbers/.docs/introduction.md | 8 + exercises/concept/numbers/.meta/Example.cs | 27 ++++ exercises/concept/numbers/.meta/config.json | 46 ++++++ exercises/concept/numbers/Numbers.cs | 14 ++ exercises/concept/numbers/Numbers.csproj | 13 ++ exercises/concept/numbers/NumbersTest.cs | 44 ++++++ exercises/concept/strings/.docs/after.md | 5 + exercises/concept/strings/.docs/hints.md | 27 ++++ .../concept/strings/.docs/instructions.md | 47 ++++++ .../concept/strings/.docs/introduction.md | 3 + exercises/concept/strings/.meta/Example.cs | 11 ++ exercises/concept/strings/.meta/config.json | 50 ++++++ exercises/concept/strings/Strings.cs | 19 +++ exercises/concept/strings/Strings.csproj | 13 ++ exercises/concept/strings/StringsTest.cs | 48 ++++++ reference/code_style.md | 49 ++++++ reference/memory_allocation.md | 28 ++++ 54 files changed, 1820 insertions(+) create mode 100644 exercises/concept/bitwise-operations/.docs/after.md create mode 100644 exercises/concept/bitwise-operations/.docs/hints.md create mode 100644 exercises/concept/bitwise-operations/.docs/instructions.md create mode 100644 exercises/concept/bitwise-operations/.docs/introduction.md create mode 100644 exercises/concept/bitwise-operations/.meta/Example.cs create mode 100644 exercises/concept/bitwise-operations/.meta/config.json create mode 100644 exercises/concept/bitwise-operations/BitwiseOperations.cs create mode 100644 exercises/concept/bitwise-operations/BitwiseOperations.csproj create mode 100644 exercises/concept/bitwise-operations/BitwiseOperationsTest.cs create mode 100644 exercises/concept/dates/.docs/after.md create mode 100644 exercises/concept/dates/.docs/hints.md create mode 100644 exercises/concept/dates/.docs/instructions.md create mode 100644 exercises/concept/dates/.docs/introduction.md create mode 100644 exercises/concept/dates/.meta/Example.cs create mode 100644 exercises/concept/dates/.meta/config.json create mode 100644 exercises/concept/dates/Dates.cs create mode 100644 exercises/concept/dates/Dates.csproj create mode 100644 exercises/concept/dates/DatesTest.cs create mode 100644 exercises/concept/enums/.docs/hints.md create mode 100644 exercises/concept/enums/.docs/instructions.md create mode 100644 exercises/concept/enums/.docs/introduction.md create mode 100644 exercises/concept/enums/.meta/Example.cs create mode 100644 exercises/concept/enums/.meta/config.json create mode 100644 exercises/concept/enums/Enums.cs create mode 100644 exercises/concept/enums/Enums.csproj create mode 100644 exercises/concept/enums/EnumsTest.cs create mode 100644 exercises/concept/numbers-floating-point/.docs/after.md create mode 100644 exercises/concept/numbers-floating-point/.docs/hints.md create mode 100644 exercises/concept/numbers-floating-point/.docs/instructions.md create mode 100644 exercises/concept/numbers-floating-point/.docs/introduction.md create mode 100644 exercises/concept/numbers-floating-point/.meta/Example.cs create mode 100644 exercises/concept/numbers-floating-point/.meta/config.json create mode 100644 exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs create mode 100644 exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj create mode 100644 exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs create mode 100644 exercises/concept/numbers/.docs/hints.md create mode 100644 exercises/concept/numbers/.docs/instructions.md create mode 100644 exercises/concept/numbers/.docs/introduction.md create mode 100644 exercises/concept/numbers/.meta/Example.cs create mode 100644 exercises/concept/numbers/.meta/config.json create mode 100644 exercises/concept/numbers/Numbers.cs create mode 100644 exercises/concept/numbers/Numbers.csproj create mode 100644 exercises/concept/numbers/NumbersTest.cs create mode 100644 exercises/concept/strings/.docs/after.md create mode 100644 exercises/concept/strings/.docs/hints.md create mode 100644 exercises/concept/strings/.docs/instructions.md create mode 100644 exercises/concept/strings/.docs/introduction.md create mode 100644 exercises/concept/strings/.meta/Example.cs create mode 100644 exercises/concept/strings/.meta/config.json create mode 100644 exercises/concept/strings/Strings.cs create mode 100644 exercises/concept/strings/Strings.csproj create mode 100644 exercises/concept/strings/StringsTest.cs create mode 100644 reference/code_style.md create mode 100644 reference/memory_allocation.md diff --git a/exercises/concept/bitwise-operations/.docs/after.md b/exercises/concept/bitwise-operations/.docs/after.md new file mode 100644 index 0000000000..0ab09c70d6 --- /dev/null +++ b/exercises/concept/bitwise-operations/.docs/after.md @@ -0,0 +1,5 @@ +# After + +- [Tutorial on working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. + +[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags diff --git a/exercises/concept/bitwise-operations/.docs/hints.md b/exercises/concept/bitwise-operations/.docs/hints.md new file mode 100644 index 0000000000..b1acd1216c --- /dev/null +++ b/exercises/concept/bitwise-operations/.docs/hints.md @@ -0,0 +1,21 @@ +# Hints + +### 1. Get default permissions for an account type + +- To handle each account type, one could use an `if` statement, but the [`switch` statement][docs.microsoft.com-switch-keyword] is a great alternative. +- Combining flags means setting a specific bit to `1` using one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. + +### 2. Grant a permission + +- Combining flags means setting a specific bit to `1` using one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. + +### 3. Revoke a permission + +- Removing a flag means setting a specific bit to `0` using a combination of two [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. + +### 4. Check for a permission + +- Checking a permission can be done by checking the result of applying one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. + +[docs.microsoft.com-bitwise-and-shift-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators +[docs.microsoft.com-switch-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch diff --git a/exercises/concept/bitwise-operations/.docs/instructions.md b/exercises/concept/bitwise-operations/.docs/instructions.md new file mode 100644 index 0000000000..28c3f78df4 --- /dev/null +++ b/exercises/concept/bitwise-operations/.docs/instructions.md @@ -0,0 +1,55 @@ +# Instructions + +In this exercise you'll be checking permissions of user accounts on an internet forum. The forum supports three different permissions: + +- Read +- Write +- Delete + +There are three types of accounts, each with different default permissions: + +- Guests: can read posts. +- Users: can read and write posts. +- Moderators: can read, write and delete posts. + +Sometimes individual permissions are modified, for example giving a guest account the permission to also write posts. + +You have four tasks. + +### 1. Get default permissions for an account type + +First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions. + +Then implement a method to return the default permissions for a specific account type: + +```csharp +Permissions.Default(AccountType.Guest) +// Returns: Permission.Read +``` + +### 2. Grant a permission + +Implement a method that grants (adds) a permission: + +```csharp +Permissions.Grant(current: Permission.None, grant: Permission.Read) +// Returns: Permission.Read +``` + +### 3. Revoke a permission + +Implement a method that revokes (removes) a permission: + +```csharp +Permissions.Revoke(current: Permission.Read, grant: Permission.Read) +// Returns: Permission.None +``` + +### 4. Check for a permission + +Implement a method that takes the current account's permissions and checks if the account is authorized for a given permission: + +```csharp +Permissions.Check(current: Permission.Write, check: Permission.Read) +// Returns: false +``` diff --git a/exercises/concept/bitwise-operations/.docs/introduction.md b/exercises/concept/bitwise-operations/.docs/introduction.md new file mode 100644 index 0000000000..fe79fe7445 --- /dev/null +++ b/exercises/concept/bitwise-operations/.docs/introduction.md @@ -0,0 +1,3 @@ +# Introduction + +The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can mark the `enum` as one which constants are _flags_. By carefully assigning the values of each constant, one can use bitwise operators to add or remove references to one or more of the (flag) constants. diff --git a/exercises/concept/bitwise-operations/.meta/Example.cs b/exercises/concept/bitwise-operations/.meta/Example.cs new file mode 100644 index 0000000000..bd3cda627f --- /dev/null +++ b/exercises/concept/bitwise-operations/.meta/Example.cs @@ -0,0 +1,39 @@ +using System; + +public enum AccountType +{ + Guest, + User, + Moderator +} + +[Flags] +public enum Permission +{ + None = 0b_0000_0000, + Read = 0b_0000_0001, + Write = 0b_0000_0010, + Delete = 0b_0000_0100, + All = Read | Write | Delete +} + +public static class Permissions +{ + public static Permission Default(AccountType accountType) => + accountType switch + { + AccountType.Guest => Permission.Read, + AccountType.User => Permission.Read | Permission.Write, + AccountType.Moderator => Permission.Read | Permission.Write | Permission.Delete, + _ => Permission.None + }; + + public static Permission Grant(Permission current, Permission grant) => + current | grant; + + public static Permission Revoke(Permission current, Permission revoke) => + current & ~revoke; + + public static bool Check(Permission current, Permission check) => + current.HasFlag(check); +} \ No newline at end of file diff --git a/exercises/concept/bitwise-operations/.meta/config.json b/exercises/concept/bitwise-operations/.meta/config.json new file mode 100644 index 0000000000..9e648d5259 --- /dev/null +++ b/exercises/concept/bitwise-operations/.meta/config.json @@ -0,0 +1,94 @@ +{ + "solution_files": ["BitwiseOperations.cs"], + "test_file": "BitwiseOperationsTest.cs", + "tests": [ + { + "name": "DefaultForGuest", + "cmd": "Permissions.Default(AccountType.Guest)" + }, + { + "name": "DefaultForUser", + "cmd": "Permissions.Default(AccountType.User)" + }, + { + "name": "DefaultForModerator", + "cmd": "Permissions.Default(AccountType.Moderator)" + }, + { + "name": "DefaultForUnknown", + "cmd": "Permissions.Default((AccountType)123)" + }, + { + "name": "GrantReadToNone", + "cmd": "Permissions.Grant(Permission.None, Permission.Read)" + }, + { + "name": "GrantReadToRead", + "cmd": "Permissions.Grant(Permission.Read, Permission.Read)" + }, + { + "name": "GrantAllToNone", + "cmd": "Permissions.Grant(Permission.None, Permission.All)" + }, + { + "name": "GrantDeleteToReadAndWrite", + "cmd": "Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)" + }, + { + "name": "GrantReadAndWriteToNone", + "cmd": "Permissions.Grant(Permission.None, Permission.Read | Permission.Write)" + }, + { + "name": "RevokeNoneFromRead", + "cmd": "Permissions.Revoke(Permission.Read, Permission.None)" + }, + { + "name": "RevokeWriteFromWrite", + "cmd": "Permissions.Revoke(Permission.Write, Permission.Write)" + }, + { + "name": "RevokeDeleteFromAll", + "cmd": "Permissions.Revoke(Permission.All, Permission.Delete)" + }, + { + "name": "RevokeReadAndWriteFromWriteAndDelete", + "cmd": "Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)" + }, + { + "name": "RevokeAllFromReadAndWrite", + "cmd": "Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)" + }, + { + "name": "CheckNoneForRead", + "cmd": "Permissions.Check(Permission.None, Permission.Read)" + }, + { + "name": "CheckWriteForWrite", + "cmd": "Permissions.Check(Permission.Write, Permission.Write)" + }, + { + "name": "CheckAllForWrite", + "cmd": "Permissions.Check(Permission.All, Permission.Write)" + }, + { + "name": "CheckReadAndWriteForRead", + "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read)" + }, + { + "name": "CheckAllForReadAndWrite", + "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)" + }, + { + "name": "CheckReadAndWriteForReadAndWrite", + "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)" + }, + { + "name": "CheckReadAndWriteForReadAndDelete", + "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)" + }, + { + "name": "CheckReadAndWriteAndDeleteForAll", + "cmd": "Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)" + } + ] +} diff --git a/exercises/concept/bitwise-operations/BitwiseOperations.cs b/exercises/concept/bitwise-operations/BitwiseOperations.cs new file mode 100644 index 0000000000..36ae239a1c --- /dev/null +++ b/exercises/concept/bitwise-operations/BitwiseOperations.cs @@ -0,0 +1,28 @@ +using System; + +// TODO: define AccountType enum + +// TODO: define Permission enum + +public static class Permissions +{ + public static Permission Default(AccountType accountType) + { + throw new NotImplementedException("Please implement the Permissions.Default method"); + } + + public static Permission Grant(Permission current, Permission grant) + { + throw new NotImplementedException("Please implement the Permissions.Grant method"); + } + + public static Permission Revoke(Permission current, Permission revoke) + { + throw new NotImplementedException("Please implement the Permissions.Revoke method"); + } + + public static bool Check(Permission current, Permission check) + { + throw new NotImplementedException("Please implement the Permissions.Check method"); + } +} \ No newline at end of file diff --git a/exercises/concept/bitwise-operations/BitwiseOperations.csproj b/exercises/concept/bitwise-operations/BitwiseOperations.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/bitwise-operations/BitwiseOperations.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/bitwise-operations/BitwiseOperationsTest.cs b/exercises/concept/bitwise-operations/BitwiseOperationsTest.cs new file mode 100644 index 0000000000..9e4a71e1a1 --- /dev/null +++ b/exercises/concept/bitwise-operations/BitwiseOperationsTest.cs @@ -0,0 +1,92 @@ +using Xunit; + +public class PermissionsTest +{ + [Fact] + public void DefaultForGuest() => + Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest)); + + [Fact] + public void DefaultForUser() => + Assert.Equal(Permission.Read | Permission.Write, Permissions.Default(AccountType.User)); + + [Fact] + public void DefaultForModerator() => + Assert.Equal(Permission.Read | Permission.Write | Permission.Delete, Permissions.Default(AccountType.Moderator)); + + [Fact] + public void DefaultForUnknown() => + Assert.Equal(Permission.None, Permissions.Default((AccountType)123)); + + [Fact] + public void GrantReadToNone() => + Assert.Equal(Permission.Read, Permissions.Grant(Permission.None, Permission.Read)); + + [Fact] + public void GrantReadToRead() => + Assert.Equal(Permission.Read, Permissions.Grant(Permission.Read, Permission.Read)); + + [Fact] + public void GrantAllToNone() => + Assert.Equal(Permission.All, Permissions.Grant(Permission.None, Permission.All)); + + [Fact] + public void GrantDeleteToReadAndWrite() => + Assert.Equal(Permission.All, Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)); + + [Fact] + public void GrantReadAndWriteToNone() => + Assert.Equal(Permission.Read | Permission.Write, Permissions.Grant(Permission.None, Permission.Read | Permission.Write)); + + [Fact] + public void RevokeNoneFromRead() => + Assert.Equal(Permission.Read, Permissions.Revoke(Permission.Read, Permission.None)); + + [Fact] + public void RevokeWriteFromWrite() => + Assert.Equal(Permission.None, Permissions.Revoke(Permission.Write, Permission.Write)); + + [Fact] + public void RevokeDeleteFromAll() => + Assert.Equal(Permission.Read | Permission.Write, Permissions.Revoke(Permission.All, Permission.Delete)); + + [Fact] + public void RevokeReadAndWriteFromWriteAndDelete() => + Assert.Equal(Permission.Delete, Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)); + + [Fact] + public void RevokeAllFromReadAndWrite() => + Assert.Equal(Permission.None, Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)); + + [Fact] + public void CheckNoneForRead() => + Assert.False(Permissions.Check(Permission.None, Permission.Read)); + + [Fact] + public void CheckWriteForWrite() => + Assert.True(Permissions.Check(Permission.Write, Permission.Write)); + + [Fact] + public void CheckAllForWrite() => + Assert.True(Permissions.Check(Permission.All, Permission.Write)); + + [Fact] + public void CheckReadAndWriteForRead() => + Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read)); + + [Fact] + public void CheckAllForReadAndWrite() => + Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); + + [Fact] + public void CheckReadAndWriteForReadAndWrite() => + Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); + + [Fact] + public void CheckReadAndWriteForReadAndDelete() => + Assert.False(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)); + + [Fact] + public void CheckReadAndWriteAndDeleteForAll() => + Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); +} \ No newline at end of file diff --git a/exercises/concept/dates/.docs/after.md b/exercises/concept/dates/.docs/after.md new file mode 100644 index 0000000000..65d47978cc --- /dev/null +++ b/exercises/concept/dates/.docs/after.md @@ -0,0 +1,5 @@ +# After + +- Interpolated strings support [specifying format strings][docs.microsoft.com_specify-a-format-string-for-an-interpolation-expression] for their interpolated values. + +[docs.microsoft.com_specify-a-format-string-for-an-interpolation-expression]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation#how-to-specify-a-format-string-for-an-interpolation-expression diff --git a/exercises/concept/dates/.docs/hints.md b/exercises/concept/dates/.docs/hints.md new file mode 100644 index 0000000000..41dfaf0073 --- /dev/null +++ b/exercises/concept/dates/.docs/hints.md @@ -0,0 +1,29 @@ +# Hints + +### General + +- [Tutorial on dates and time by csharp.net][csharp.net-dates-working-with-dates-time] + +### 1. Parse appointment date + +- The `DateTime` class has several methods to [parse][docs.microsoft.com_parsing-date] a `string` to a `DateTime`. + +### 2. Check if an appointment has already passed + +- `DateTime` objects can be compared using the default [comparison operators][docs.microsoft.com_datetime-operators]. + +### 3. Check if appointment is in the afternoon + +- Accessing the time portion of a `DateTime` object can de done through one of its [properties][docs.microsoft.com_datetime-properties]. + +### 4. Describe the time and date of the appointment + +- The tests are running as if running on a machine in the United States, which means that when converting a `DateTime` to a `string` will return dates and time in US format. +- When converting a `DateTime` instance to a `string`, you can use either a [standard format string][docs.microsoft.com_standard-date-and-time-format-strings] or a [custom format string][docs.microsoft.com_custom-date-and-time-format-strings]. + +[docs.microsoft.com_parsing-date]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime +[docs.microsoft.com_datetime-operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netframework-4.8#operators +[docs.microsoft.com_datetime-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.0#properties +[docs.microsoft.com_standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[docs.microsoft.com_custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings +[csharp.net-dates-working-with-dates-time]: https://csharp.net-tutorials.com/data-types/working-with-dates-time/ diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md new file mode 100644 index 0000000000..0bceca05da --- /dev/null +++ b/exercises/concept/dates/.docs/instructions.md @@ -0,0 +1,48 @@ +# Instructions + +In this exercise you'll be working on an appointment scheduler for a beauty salon in New York. + +You have four tasks, which will all involve appointment dates. The dates and times will use one of the following four formats: + +- `"7/25/2019 13:45:00"` +- `"July 25, 2019 13:45:00"` +- `"Thursday, July 25, 2019 13:45:00:00"` +- `"July 25, 2019 13:45:00"` + +The tests will automatically set the culture to `en-US` - you don't have to set or specify the culture yourselves. + +### 1. Parse appointment date + +Implement a method that can parse a textual representation of an appointment date into the corresponding `DateTime` format: + +```csharp +Appointment.Schedule("7/25/2019 13:45:00") +// Returns: new DateTime(2019, 7, 25, 13, 45, 0) +``` + +### 2. Check if an appointment has already passed + +Implement a method that takes an appointment date and checks if the appointment was somewhere in the past: + +```csharp +Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) +// Returns: true +``` + +### 3. Check if appointment is in the afternoon + +Implement a method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): + +```csharp +Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) +// Returns: true +``` + +### 4. Describe the time and date of the appointment + +Implement a method that takes an appointment date and returns a description of that date and time: + +```csharp +Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) +// Returns: "You have an appointment on Friday 29 March 2019 at 15:00." +``` diff --git a/exercises/concept/dates/.docs/introduction.md b/exercises/concept/dates/.docs/introduction.md new file mode 100644 index 0000000000..1d2564fea8 --- /dev/null +++ b/exercises/concept/dates/.docs/introduction.md @@ -0,0 +1,7 @@ +# Introduction + +The C# `DateTime` type is a type that contains both date and time information. + +The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`. + +Understanding which `DateTime` methods are culture-dependent is important to know. In general, any `DateTime` method that deals with `string`s (either as input or output) will be dependent on the current culture. diff --git a/exercises/concept/dates/.meta/Example.cs b/exercises/concept/dates/.meta/Example.cs new file mode 100644 index 0000000000..761a8ef273 --- /dev/null +++ b/exercises/concept/dates/.meta/Example.cs @@ -0,0 +1,16 @@ +using System; + +public static class Appointment +{ + public static DateTime Schedule(string appointmentDateDescription) => + DateTime.Parse(appointmentDateDescription); + + public static bool HasPassed(DateTime appointmentDate) => + appointmentDate < DateTime.Now; + + public static bool IsAfternoonAppointment(DateTime appointmentDate) => + appointmentDate.Hour >= 12 && appointmentDate.Hour < 18; + + public static string Description(DateTime appointmentDate) => + $"You have an appointment on {appointmentDate:dddd d MMMM yyyy} at {appointmentDate:HH:mm}."; +} \ No newline at end of file diff --git a/exercises/concept/dates/.meta/config.json b/exercises/concept/dates/.meta/config.json new file mode 100644 index 0000000000..56c5c4637b --- /dev/null +++ b/exercises/concept/dates/.meta/config.json @@ -0,0 +1,102 @@ +{ + "solution_files": ["Dates.cs"], + "test_file": "DatesTest.cs", + "tests": [ + { + "name": "ScheduleDateUsingOnlyNumbers", + "cmd": "Appointment.Schedule(\"7/25/2019 13:45:00\")" + }, + { + "name": "ScheduleDateWithTextualMonth", + "cmd": "Appointment.Schedule(\"June 3, 2019 11:30:00\")" + }, + { + "name": "ScheduleDateWithTextualMonthAndWeekday", + "cmd": "Appointment.Schedule(\"Thursday, December 5, 2019 09:00:00\")" + }, + { + "name": "HasPassedWithAppointmentOneYearAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))" + }, + { + "name": "HasPassedWithAppointmentMonthsAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMonths(-8))" + }, + { + "name": "HasPassedWithAppointmentDaysAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddDays(-23))" + }, + { + "name": "HasPassedWithAppointmentHoursAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddHours(-12))" + }, + { + "name": "HasPassedWithAppointmentMinutesAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(-55))" + }, + { + "name": "HasPassedWithAppointmentOneMinuteAgo", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(-1))" + }, + { + "name": "HasPassedWithAppointmentInOneMinute", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(1))" + }, + { + "name": "HasPassedWithAppointmentInMinutes", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(5))" + }, + { + "name": "HasPassedWithAppointmentInDays", + "cmd": "Appointment.HasPassed(DateTime.Now.AddDays(19))" + }, + { + "name": "HasPassedWithAppointmentInMonths", + "cmd": "Appointment.HasPassed(DateTime.Now.AddMonths(10))" + }, + { + "name": "HasPassedWithAppointmentInYears", + "cmd": "Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))" + }, + { + "name": "IsAfternoonAppointmentForEarlyMorningAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))" + }, + { + "name": "IsAfternoonAppointmentForLateMorningAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))" + }, + { + "name": "IsAfternoonAppointmentForNoonAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))" + }, + { + "name": "IsAfternoonAppointmentForEarlyAfternoonAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))" + }, + { + "name": "IsAfternoonAppointmentForLateAfternoonAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))" + }, + { + "name": "IsAfternoonAppointmentForEarlyEveningAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))" + }, + { + "name": "IsAfternoonAppointmentForLateEveningAppointment", + "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))" + }, + { + "name": "DescriptionOnFridayAfternoon", + "cmd": "Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))" + }, + { + "name": "DescriptionOnThursdayAfternoon", + "cmd": "Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))" + }, + { + "name": "DescriptionOnWednesdayMorning", + "cmd": "Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))" + } + ] +} diff --git a/exercises/concept/dates/Dates.cs b/exercises/concept/dates/Dates.cs new file mode 100644 index 0000000000..166c158d3d --- /dev/null +++ b/exercises/concept/dates/Dates.cs @@ -0,0 +1,24 @@ +using System; + +public static class Appointment +{ + public static DateTime Schedule(string appointmentDateDescription) + { + throw new NotImplementedException("Please implement the Appointment.Schedule method"); + } + + public static bool HasPassed(DateTime appointmentDate) + { + throw new NotImplementedException("Please implement the Appointment.HasPassed method"); + } + + public static bool IsAfternoonAppointment(DateTime appointmentDate) + { + throw new NotImplementedException("Please implement the Appointment.IsAfternoonAppointment method"); + } + + public static string Description(DateTime appointmentDate) + { + throw new NotImplementedException("Please implement the Appointment.Description method"); + } +} \ No newline at end of file diff --git a/exercises/concept/dates/Dates.csproj b/exercises/concept/dates/Dates.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/dates/Dates.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/dates/DatesTest.cs b/exercises/concept/dates/DatesTest.cs new file mode 100644 index 0000000000..0f943d2506 --- /dev/null +++ b/exercises/concept/dates/DatesTest.cs @@ -0,0 +1,145 @@ +using Xunit; +using System; +using System.Globalization; +using System.Reflection; +using System.Threading; +using Xunit.Sdk; + +[UseCulture("en-US")] +public class AppointmentTest +{ + [Fact] + public void ScheduleDateUsingOnlyNumbers() => + Assert.Equal(new DateTime(2019, 07, 25, 13, 45, 0), Appointment.Schedule("7/25/2019 13:45:00")); + + [Fact] + public void ScheduleDateWithTextualMonth() => + Assert.Equal(new DateTime(2019, 6, 3, 11, 30, 0), Appointment.Schedule("June 3, 2019 11:30:00")); + + [Fact] + public void ScheduleDateWithTextualMonthAndWeekday() => + Assert.Equal(new DateTime(2019, 12, 5, 9, 0, 0), Appointment.Schedule("Thursday, December 5, 2019 09:00:00")); + + [Fact] + public void HasPassedWithAppointmentOneYearAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))); + + [Fact] + public void HasPassedWithAppointmentMonthsAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddMonths(-8))); + + [Fact] + public void HasPassedWithAppointmentDaysAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddDays(-23))); + + [Fact] + public void HasPassedWithAppointmentHoursAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddHours(-12))); + + [Fact] + public void HasPassedWithAppointmentMinutesAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-55))); + + [Fact] + public void HasPassedWithAppointmentOneMinuteAgo() => + Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-1))); + + [Fact] + public void HasPassedWithAppointmentInOneMinute() => + Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(1))); + + [Fact] + public void HasPassedWithAppointmentInMinutes() => + Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(5))); + + [Fact] + public void HasPassedWithAppointmentInDays() => + Assert.False(Appointment.HasPassed(DateTime.Now.AddDays(19))); + + [Fact] + public void HasPassedWithAppointmentInMonths() => + Assert.False(Appointment.HasPassed(DateTime.Now.AddMonths(10))); + + [Fact] + public void HasPassedWithAppointmentInYears() => + Assert.False(Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))); + + [Fact] + public void IsAfternoonAppointmentForEarlyMorningAppointment() => + Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))); + + [Fact] + public void IsAfternoonAppointmentForLateMorningAppointment() => + Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))); + + [Fact] + public void IsAfternoonAppointmentForNoonAppointment() => + Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))); + + [Fact] + public void IsAfternoonAppointmentForEarlyAfternoonAppointment() => + Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))); + + [Fact] + public void IsAfternoonAppointmentForLateAfternoonAppointment() => + Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))); + + [Fact] + public void IsAfternoonAppointmentForEarlyEveningAppointment() => + Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))); + + [Fact] + public void IsAfternoonAppointmentForLateEveningAppointment() => + Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))); + + [Fact] + public void DescriptionOnFridayAfternoon() => + Assert.Equal("You have an appointment on Friday 29 March 2019 at 15:00.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); + + [Fact] + public void DescriptionOnThursdayAfternoon() => + Assert.Equal("You have an appointment on Thursday 25 July 2019 at 13:45.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); + + [Fact] + public void DescriptionOnWednesdayMorning() => + Assert.Equal("You have an appointment on Wednesday 9 September 2020 at 09:09.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); + + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] + private class UseCultureAttribute : BeforeAfterTestAttribute + { + private readonly CultureInfo _culture; + private readonly CultureInfo _uiCulture; + private CultureInfo _originalCulture; + private CultureInfo _originalUiCulture; + + public UseCultureAttribute(string culture) + : this(culture, culture) { } + + public UseCultureAttribute(string culture, string uiCulture) + { + _culture = new CultureInfo(culture, false); + _uiCulture = new CultureInfo(uiCulture, false); + } + + public override void Before(MethodInfo methodUnderTest) + { + _originalCulture = Thread.CurrentThread.CurrentCulture; + _originalUiCulture = Thread.CurrentThread.CurrentUICulture; + + Thread.CurrentThread.CurrentCulture = _culture; + Thread.CurrentThread.CurrentUICulture = _uiCulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + + public override void After(MethodInfo methodUnderTest) + { + Thread.CurrentThread.CurrentCulture = _originalCulture; + Thread.CurrentThread.CurrentUICulture = _originalUiCulture; + + CultureInfo.CurrentCulture.ClearCachedData(); + CultureInfo.CurrentUICulture.ClearCachedData(); + } + } +} \ No newline at end of file diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/enums/.docs/hints.md new file mode 100644 index 0000000000..7f495cb19a --- /dev/null +++ b/exercises/concept/enums/.docs/hints.md @@ -0,0 +1,23 @@ +# Hints + +### General + +- [Tutorial on working with enums][docs.microsoft.com-enumeration-types]. + +### 1. Parse log level + +- The `Enum` class has several [utility methods][docs.microsoft.com_system.enum-methods] to help with converting (parsing) a string to an enum. +- There is an option to ignore casing when parsing an enum. + +### 2. Support unknown log level + +- The `Enum` class' parsing methods also have similar methods that don't fail when not being able to parse an enum. + +### 3. Convert log line to short format + +- Converting an enum to a number can be done through [casting][docs.microsoft.com_enumeration-types-casting] or by using a [format string][docs.microsoft.com_system.enum.tostring]. + +[docs.microsoft.com-enumeration-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types +[docs.microsoft.com_system.enum-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#methods +[docs.microsoft.com_system.enum.tostring]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.tostring?view=netcore-3.0 +[docs.microsoft.com_enumeration-types-casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#code-try-1 diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md new file mode 100644 index 0000000000..a34b97cf70 --- /dev/null +++ b/exercises/concept/enums/.docs/instructions.md @@ -0,0 +1,55 @@ +# Instructions + +In this exercise you'll be processing log-lines. + +Each log line is a string formatted as follows: `"[]: "`. + +There are three different log levels: + +- `INFO` +- `WARNING` +- `ERROR` + +You have three tasks. + +### 1. Parse log level + +Define a `LogLevel` enum that has three elements: + +- `Info` +- `Warning` +- `Error` + +Next, implement a method to parse the log level of a log line: + +```csharp +LogLine.ParseLogLevel("[INFO]: File deleted") +// Returns: LogLevel.Info +``` + +### 2. Support unknown log level + +Unfortunately, occasionally some log lines have an unknown log level. To gracefully handle these log lines, add an `Unknown` element to the `LogLevel` enum which should be returned when parsing an unknown log level: + +```csharp +LogLine.ParseLogLevel("[FATAL]: Invalid operation") +// Returns: LogLevel.Unknown +``` + +### 3. Convert log line to short format + +The log level of a log line is quite verbose. To reduce the disk space needed to store the log lines, a short format is developed: `"[]:"`. + +The encoded log level is simple mapping of a log level to a number: + +- `Unknown` -> `0` +- `Info` -> `1` +- `Warning` -> `2` +- `Error` -> `4` + +Implement a method that can output the shortened log line format: + +```csharp +LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") +// Returns: "4:Stack overflow" +``` diff --git a/exercises/concept/enums/.docs/introduction.md b/exercises/concept/enums/.docs/introduction.md new file mode 100644 index 0000000000..3121166b9e --- /dev/null +++ b/exercises/concept/enums/.docs/introduction.md @@ -0,0 +1,3 @@ +# Introduction + +The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/enums/.meta/Example.cs new file mode 100644 index 0000000000..2660a675d0 --- /dev/null +++ b/exercises/concept/enums/.meta/Example.cs @@ -0,0 +1,21 @@ +using System; + +public enum LogLevel +{ + Unknown = 0, + Info = 1, + Warning = 2, + Error = 4 +} + +public static class LogLine +{ + public static LogLevel ParseLogLevel(string logLine) => + Enum.TryParse(GetLogLevel(logLine), ignoreCase: true, out var logLevel) ? logLevel : LogLevel.Unknown; + + private static string GetLogLevel(string logLine) => + logLine[1..(logLine.IndexOf(']'))]; + + public static string OutputForShortLog(LogLevel logLevel, string message) => + $"{logLevel:D}:{message}"; +} \ No newline at end of file diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/enums/.meta/config.json new file mode 100644 index 0000000000..e6378f8d6f --- /dev/null +++ b/exercises/concept/enums/.meta/config.json @@ -0,0 +1,38 @@ +{ + "solution_files": ["Enums.cs"], + "test_file": "EnumsTest.cs", + "tests": [ + { + "name": "ParseError", + "cmd": "LogLine.ParseLogLevel(\"[ERROR]: Disk full\")" + }, + { + "name": "ParseWarning", + "cmd": "LogLine.ParseLogLevel(\"[WARNING]: Timezone not set\")" + }, + { + "name": "ParseInfo", + "cmd": "LogLine.ParseLogLevel(\"[INFO]: Timezone changed\")" + }, + { + "name": "ParseUnknown", + "cmd": "LogLine.ParseLogLevel(\"[FATAL]: Crash!\")" + }, + { + "name": "OutputForShortLogForError", + "cmd": "LogLine.OutputForShortLog(LogLevel.Error, \"Stack overflow\")" + }, + { + "name": "OutputForShortLogForWarning", + "cmd": "LogLine.OutputForShortLog(LogLevel.Warning, \"Unsafe password\")" + }, + { + "name": "OutputForShortLogForInfo", + "cmd": "LogLine.OutputForShortLog(LogLevel.Info, \"File moved\")" + }, + { + "name": "OutputForShortLogForUnknown", + "cmd": "LogLine.OutputForShortLog(LogLevel.Unknown, \"Something unknown happened\")" + } + ] +} diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs new file mode 100644 index 0000000000..43371916ec --- /dev/null +++ b/exercises/concept/enums/Enums.cs @@ -0,0 +1,16 @@ +using System; + +// TODO: define LogLevel enum + +public static class LogLine +{ + public static LogLevel ParseLogLevel(string logLine) + { + throw new NotImplementedException("Please implement the LogLine.ParseLogLevel method"); + } + + public static string OutputForShortLog(LogLevel logLevel, string message) + { + throw new NotImplementedException("Please implement the LogLine.OutputForShortLog method"); + } +} \ No newline at end of file diff --git a/exercises/concept/enums/Enums.csproj b/exercises/concept/enums/Enums.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/enums/Enums.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/enums/EnumsTest.cs b/exercises/concept/enums/EnumsTest.cs new file mode 100644 index 0000000000..a36e121d29 --- /dev/null +++ b/exercises/concept/enums/EnumsTest.cs @@ -0,0 +1,36 @@ +using Xunit; + +public class LogLineTest +{ + [Fact] + public void ParseError() => + Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERROR]: Disk full")); + + [Fact] + public void ParseWarning() => + Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WARNING]: Timezone not set")); + + [Fact] + public void ParseInfo() => + Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INFO]: Timezone changed")); + + [Fact] + public void ParseUnknown() => + Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[FATAL]: Crash!")); + + [Fact] + public void OutputForShortLogForError() => + Assert.Equal("4:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); + + [Fact] + public void OutputForShortLogForWarning() => + Assert.Equal("2:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); + + [Fact] + public void OutputForShortLogForInfo() => + Assert.Equal("1:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); + + [Fact] + public void OutputForShortLogForUnknown() => + Assert.Equal("0:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); +} \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md new file mode 100644 index 0000000000..67d326f0e8 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -0,0 +1,15 @@ +# After + +- See the [characteristics of the floating-point types table][docs-microsoft.com-characteristics-of-the-floating-point-types] for an overview of the precision, approximate range and size of the three floating-point types. + +- Converting between numeric types is sometimes [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but at other times [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. + +- Be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. + +- You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. + +[docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions +[docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions +[docs-microsoft.com-characteristics-of-the-floating-point-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types +[docs.microsoft.com_precision-in-comparisons]: https://docs.microsoft.com/en-us/dotnet/api/system.double.equals#precision-in-comparisons +[0.30000000000000004.com]: https://0.30000000000000004.com/ diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/numbers-floating-point/.docs/hints.md new file mode 100644 index 0000000000..6e5e807dc7 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.docs/hints.md @@ -0,0 +1,22 @@ +# Hints + +### General + +- [Floating-point numeric types introduction][docs.microsoft.com-floating_point_numeric_types]. + +### 1. Calculate the annual percentage yield + +- By default, any floating-point number defined in C# code is treated as a `double`. To use a different floating-point type (like `float` or `decimal`), one must add the appropriate [suffix][docs.microsoft.com-real_literals] to the number. + +### 2. Calculate the annual balance update + +- When calculating the annual yield, it might be useful to temporarily convert a negative balance to a positive one. One could use arithmetic here, or one of the methods in the [`Math` class][docs-microsoft.com-system.math]. + +### 3. Calculate the years before reaching the desired balance + +- To calculate the years, one has to loop over the balance. C# has several [looping constructs][docs.microsoft.com-loops]. + +[docs-microsoft.com-system.math]: https://docs.microsoft.com/en-us/dotnet/api/system.math?view=netcore-3.0 +[docs.microsoft.com-floating_point_numeric_types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types +[docs.microsoft.com-real_literals]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#real-literals +[docs.microsoft.com-loops]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/branches-and-loops-local#use-loops-to-repeat-operations diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/numbers-floating-point/.docs/instructions.md new file mode 100644 index 0000000000..6ef0972949 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.docs/instructions.md @@ -0,0 +1,45 @@ +# Instructions + +In this exercise you'll be working with savings accounts. Each year, the balance of each savings account is updated based on the [annual percentage yield][wikipedia-annual_percentage_yield] (APY). The APY value depends on the amount of money in the account (its balance): + +- -3.213% for a negative balance. +- 0.5% for a positive balance less than `1000`. +- 1.621% for a positive balance greater or equal than `1000` and less than `5000`. +- 2.475% for a positive balance greater or equal than `5000`. + +You have three tasks, each of which will deal with balances and their APYs. + +### 1. Calculate the annual percentage yield + +Implement a method to calculate the APY based on the specified balance: + +```csharp +FloatingPointNumbers.AnnualPercentageYield(balance: 200.75m) +// 0.5f +``` + +Note that the value returned is a `float`. + +### 2. Calculate the annual balance update + +Implement a method to calculate the annual balance update, taking into account the APY: + +```csharp +FloatingPointNumbers.AnnualBalanceUpdate(balance: 200.75m) +// 201.75375m +``` + +Note that the value returned is a `decimal`. + +### 3. Calculate the years before reaching the desired balance + +Implement a method to calculate the minimum number of years required to reach the desired balance: + +```csharp +FloatingPointNumbers.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88m) +// 14 +``` + +Note that the value returned is an `int`. + +[wikipedia-annual_percentage_yield]: https://en.wikipedia.org/wiki/Annual_percentage_yield diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/numbers-floating-point/.docs/introduction.md new file mode 100644 index 0000000000..50e6c0da55 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.docs/introduction.md @@ -0,0 +1,13 @@ +# Introduction + +A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. + +Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision. + +C# has three floating point types: + +- `float`: 4 bytes (~6-9 digits precision). Written as `2.45f`. +- `double`: 8 bytes (~15-17 digits precision). This is the most common type. Written as `2.45` or `2.45d`. +- `decimal`: 16 bytes (28-29 digits precision). Normally used when working with monetary data, as its precision leads to less rounding errors. Written as `2.45m`. + +As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded). diff --git a/exercises/concept/numbers-floating-point/.meta/Example.cs b/exercises/concept/numbers-floating-point/.meta/Example.cs new file mode 100644 index 0000000000..9f4ca05627 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.meta/Example.cs @@ -0,0 +1,41 @@ +using System; + +public static class SavingsAccount +{ + public static float AnnualPercentageYield(decimal balance) + { + if (balance < 0.0m) + return -3.213f; + + if (balance < 1000.0m) + return 0.5f; + + if (balance < 5000.0m) + return 1.621f; + + return 2.475f; + } + + private static decimal AnnualYield(decimal balance) + { + var multiplier = (decimal)AnnualPercentageYield(balance) / 100; + return Math.Abs(balance) * multiplier; + } + + public static decimal AnnualBalanceUpdate(decimal balance) => + balance + AnnualYield(balance); + + public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalance) + { + var accumulatingBalance = balance; + var years = 0; + + while (accumulatingBalance < targetBalance) + { + accumulatingBalance = AnnualBalanceUpdate(accumulatingBalance); + years++; + } + + return years; + } +} \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/.meta/config.json b/exercises/concept/numbers-floating-point/.meta/config.json new file mode 100644 index 0000000000..af3aeb01ed --- /dev/null +++ b/exercises/concept/numbers-floating-point/.meta/config.json @@ -0,0 +1,102 @@ +{ + "solution_files": ["NumbersFloatingPoint.cs"], + "test_file": "NumbersFloatingPointTest.cs", + "tests": [ + { + "name": "MinimalFirstAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(0m)" + }, + { + "name": "TinyFirstAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(0.000001m)" + }, + { + "name": "MaximumFirstAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(999.9999m)" + }, + { + "name": "MinimalSecondAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(1_000.0m)" + }, + { + "name": "TinySecondAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(1_000.0001m)" + }, + { + "name": "MaximumSecondAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(4_999.9990m)" + }, + { + "name": "MinimalThirdAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(5_000.0000m)" + }, + { + "name": "TinyThirdAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(5_000.0001m)" + }, + { + "name": "LargeThirdAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(5_639_998.742909m)" + }, + { + "name": "MinimalNegativeAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(-0.000001m)" + }, + { + "name": "SmallNegativeAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(-0.123m)" + }, + { + "name": "RegularNegativeAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(-300.0m)" + }, + { + "name": "LargeNegativeAnnualPercentageYield", + "cmd": "SavingsAccount.AnnualPercentageYield(-152964.231m)" + }, + { + "name": "AnnualBalanceUpdateForEmptyStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(0.0m)" + }, + { + "name": "AnnualBalanceUpdateForSmallPositiveStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(0.000001m)" + }, + { + "name": "AnnualBalanceUpdateForAveragePositiveStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(1_000.0m)" + }, + { + "name": "AnnualBalanceUpdateForLargePositiveStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(1_000.0001m)" + }, + { + "name": "AnnualBalanceUpdateForHugePositiveStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)" + }, + { + "name": "AnnualBalanceUpdateForSmallNegativeStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(-0.123m)" + }, + { + "name": "AnnualBalanceUpdateForLargeNegativeStartBalance", + "cmd": "SavingsAccount.AnnualBalanceUpdate(-152964.231m)" + }, + { + "name": "YearsBeforeDesiredBalanceForSmallStartBalance", + "cmd": "SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)" + }, + { + "name": "YearsBeforeDesiredBalanceForAverageStartBalance", + "cmd": "SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)" + }, + { + "name": "YearsBeforeDesiredBalanceForLargeStartBalance", + "cmd": "SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)" + }, + { + "name": "YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance", + "cmd": "SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)" + } + ] +} diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs new file mode 100644 index 0000000000..081c2e065d --- /dev/null +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs @@ -0,0 +1,19 @@ +using System; + +public static class SavingsAccount +{ + public static float AnnualPercentageYield(decimal balance) + { + throw new NotImplementedException("Please implement the SavingsAccount.AnnualPercentageYield method"); + } + + public static decimal AnnualBalanceUpdate(decimal balance) + { + throw new NotImplementedException("Please implement the SavingsAccount.AnnualBalanceUpdate method"); + } + + public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalance) + { + throw new NotImplementedException("Please implement the SavingsAccount.YearsBeforeDesiredBalance method"); + } +} \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs new file mode 100644 index 0000000000..9bd3ba1ce8 --- /dev/null +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs @@ -0,0 +1,100 @@ +using Xunit; + +public class SavingsAccountTest +{ + [Fact] + public void MinimalFirstAnnualPercentageYield() => + Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(0m)); + + [Fact] + public void TinyFirstAnnualPercentageYield() => + Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(0.000001m)); + + [Fact] + public void MaximumFirstAnnualPercentageYield() => + Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(999.9999m)); + + [Fact] + public void MinimalSecondAnnualPercentageYield() => + Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(1_000.0m)); + + [Fact] + public void TinySecondAnnualPercentageYield() => + Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(1_000.0001m)); + + [Fact] + public void MaximumSecondAnnualPercentageYield() => + Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(4_999.9990m)); + + [Fact] + public void MinimalThirdAnnualPercentageYield() => + Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_000.0000m)); + + [Fact] + public void TinyThirdAnnualPercentageYield() => + Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_000.0001m)); + + [Fact] + public void LargeThirdAnnualPercentageYield() => + Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_639_998.742909m)); + + [Fact] + public void MinimalNegativeAnnualPercentageYield() => + Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-0.000001m)); + + [Fact] + public void SmallNegativeAnnualPercentageYield() => + Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-0.123m)); + + [Fact] + public void RegularNegativeAnnualPercentageYield() => + Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-300.0m)); + + [Fact] + public void LargeNegativeAnnualPercentageYield() => + Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-152964.231m)); + + [Fact] + public void AnnualBalanceUpdateForEmptyStartBalance() => + Assert.Equal(0.0000m, SavingsAccount.AnnualBalanceUpdate(0.0m)); + + [Fact] + public void AnnualBalanceUpdateForSmallPositiveStartBalance() => + Assert.Equal(0.000001005m, SavingsAccount.AnnualBalanceUpdate(0.000001m)); + + [Fact] + public void AnnualBalanceUpdateForAveragePositiveStartBalance() => + Assert.Equal(1016.210000m, SavingsAccount.AnnualBalanceUpdate(1_000.0m)); + + [Fact] + public void AnnualBalanceUpdateForLargePositiveStartBalance() => + Assert.Equal(1016.210101621m, SavingsAccount.AnnualBalanceUpdate(1_000.0001m)); + + [Fact] + public void AnnualBalanceUpdateForHugePositiveStartBalance() => + Assert.Equal(920352587.26744292868451875m, SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)); + + [Fact] + public void AnnualBalanceUpdateForSmallNegativeStartBalance() => + Assert.Equal(-0.12695199m, SavingsAccount.AnnualBalanceUpdate(-0.123m)); + + [Fact] + public void AnnualBalanceUpdateForLargeNegativeStartBalance() => + Assert.Equal(-157878.97174203m, SavingsAccount.AnnualBalanceUpdate(-152964.231m)); + + [Fact] + public void YearsBeforeDesiredBalanceForSmallStartBalance() => + Assert.Equal(47, SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)); + + [Fact] + public void YearsBeforeDesiredBalanceForAverageStartBalance() => + Assert.Equal(6, SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)); + + [Fact] + public void YearsBeforeDesiredBalanceForLargeStartBalance() => + Assert.Equal(5, SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)); + + [Fact] + public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() => + Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); +} \ No newline at end of file diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md new file mode 100644 index 0000000000..74197ec4fc --- /dev/null +++ b/exercises/concept/numbers/.docs/hints.md @@ -0,0 +1,20 @@ +# Hints + +### General + +- [docs.microsoft.com numbers tutorial][tutorial-docs.microsoft-numbers] + +### 1. Calculate the production rate per second + +- Determining the success rate can be done through a [conditional statement][tutorial-csharp.net-if-statement]. +- C# allows for multiplication to be applied to two different number types (such as an `int` and a `double`). It will automatically return the "largest" data type. + +[tutorial-docs.microsoft-numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local +[tutorial-csharp.net-if-statement]: https://csharp.net-tutorials.com/control-structures/if-statement/ + +### 2. Calculate the number of working items produced per second + +- Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][docs-microsoft.com-convert] or [cast to an int][tutorial-dotnetperls.com-cast-int]. + +[docs-microsoft.com-convert]: https://docs.microsoft.com/en-us/dotnet/api/system.convert?view=netcore-3.0#examples +[tutorial-dotnetperls.com-cast-int]: https://www.dotnetperls.com/cast-int diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md new file mode 100644 index 0000000000..bf2c6856a1 --- /dev/null +++ b/exercises/concept/numbers/.docs/instructions.md @@ -0,0 +1,34 @@ +# Instructions + +In this exercise you'll be writing code to analyze the production of an assembly line in a car factory. The assembly line's speed can range from `0` (off) to `10` (maximum). + +At its default speed (`1`), `221` cars are produced each hour. In principle, the production increases linearly. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate: + +- `0`: 0% success rate. +- `1` to `4`: 100% success rate. +- `5` to `8`: 90% success rate. +- `9` and `10`: 77% success rate. + +You have two tasks. + +### 1. Calculate the production rate per hour + +Implement a method to calculate the assembly line's production rate per hour, taking into account its success rate: + +```csharp +AssemblyLine.ProductionRatePerHour(speed: 6) +// Returns: 1193.4 +``` + +Note that the value returned is a `double`. + +### 2. Calculate the number of working items produced per minute + +Implement a method to calculate how many working cars are produced per minute: + +```csharp +AssemblyLine.WorkingItemsPerMinute(speed: 6) +// Returns: 19 +``` + +Note that the value returned is an `int`. diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md new file mode 100644 index 0000000000..18b2d775bd --- /dev/null +++ b/exercises/concept/numbers/.docs/introduction.md @@ -0,0 +1,8 @@ +# Introduction + +There are two different types of numbers in C#: + +- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. +- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. + +The two most common numeric types in C# are `int` and `double`. An `int` is a signed 32-bit integer and a `double` is a 64-bit floating-point number. diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs new file mode 100644 index 0000000000..cdd919471e --- /dev/null +++ b/exercises/concept/numbers/.meta/Example.cs @@ -0,0 +1,27 @@ +public static class AssemblyLine +{ + private const int ProductionRatePerHourForDefaultSpeed = 221; + + public static double ProductionRatePerHour(int speed) => + ProductionRatePerHourForSpeed(speed) * SuccessRate(speed); + + private static int ProductionRatePerHourForSpeed(int speed) => + ProductionRatePerHourForDefaultSpeed * speed; + + public static int WorkingItemsPerMinute(int speed) => + (int)ProductionRatePerHour(speed) / 60; + + private static double SuccessRate(int speed) + { + if (speed == 0) + return 0.0; + + if (speed >= 9) + return 0.77; + + if (speed < 5) + return 1.0; + + return 0.9; + } +} \ No newline at end of file diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json new file mode 100644 index 0000000000..5579d4392a --- /dev/null +++ b/exercises/concept/numbers/.meta/config.json @@ -0,0 +1,46 @@ +{ + "solution_files": ["Numbers.cs"], + "test_file": "NumbersTest.cs", + "tests": [ + { + "name": "ProductionRatePerHourForSpeedZero", + "cmd": "AssemblyLine.ProductionRatePerHour(0)" + }, + { + "name": "ProductionRatePerHourForSpeedOne", + "cmd": "AssemblyLine.ProductionRatePerHour(1)" + }, + { + "name": "ProductionRatePerHourForSpeedFour", + "cmd": "AssemblyLine.ProductionRatePerHour(4)" + }, + { + "name": "ProductionRatePerHourForSpeedSeven", + "cmd": "AssemblyLine.ProductionRatePerHour(7)" + }, + { + "name": "ProductionRatePerHourForSpeedNine", + "cmd": "AssemblyLine.ProductionRatePerHour(9)" + }, + { + "name": "WorkingItemsPerMinuteForSpeedZero", + "cmd": "AssemblyLine.WorkingItemsPerMinute(0)" + }, + { + "name": "WorkingItemsPerMinuteForSpeedOne", + "cmd": "AssemblyLine.WorkingItemsPerMinute(1)" + }, + { + "name": "WorkingItemsPerMinuteForSpeedFive", + "cmd": "AssemblyLine.WorkingItemsPerMinute(5)" + }, + { + "name": "WorkingItemsPerMinuteForSpeedFour", + "cmd": "AssemblyLine.WorkingItemsPerMinute(8)" + }, + { + "name": "WorkingItemsPerMinuteForSpeedTen", + "cmd": "AssemblyLine.WorkingItemsPerMinute(10)" + } + ] +} diff --git a/exercises/concept/numbers/Numbers.cs b/exercises/concept/numbers/Numbers.cs new file mode 100644 index 0000000000..c888768923 --- /dev/null +++ b/exercises/concept/numbers/Numbers.cs @@ -0,0 +1,14 @@ +using System; + +public static class AssemblyLine +{ + public static double ProductionRatePerHour(int speed) + { + throw new NotImplementedException("Please implement the AssemblyLine.ProductionRatePerHour method"); + } + + public static int WorkingItemsPerMinute(int speed) + { + throw new NotImplementedException("Please implement the AssemblyLine.WorkingItemsPerMinute method"); + } +} \ No newline at end of file diff --git a/exercises/concept/numbers/Numbers.csproj b/exercises/concept/numbers/Numbers.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/numbers/Numbers.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/numbers/NumbersTest.cs b/exercises/concept/numbers/NumbersTest.cs new file mode 100644 index 0000000000..38fc5138c4 --- /dev/null +++ b/exercises/concept/numbers/NumbersTest.cs @@ -0,0 +1,44 @@ +using Xunit; + +public class AssemblyLineTest +{ + [Fact] + public void ProductionRatePerHourForSpeedZero() => + Assert.Equal(0.0, AssemblyLine.ProductionRatePerHour(0)); + + [Fact] + public void ProductionRatePerHourForSpeedOne() => + Assert.Equal(221.0, AssemblyLine.ProductionRatePerHour(1)); + + [Fact] + public void ProductionRatePerHourForSpeedFour() => + Assert.Equal(884.0, AssemblyLine.ProductionRatePerHour(4)); + + [Fact] + public void ProductionRatePerHourForSpeedSeven() => + Assert.Equal(1392.3, AssemblyLine.ProductionRatePerHour(7)); + + [Fact] + public void ProductionRatePerHourForSpeedNine() => + Assert.Equal(1531.53, AssemblyLine.ProductionRatePerHour(9)); + + [Fact] + public void WorkingItemsPerMinuteForSpeedZero() => + Assert.Equal(0, AssemblyLine.WorkingItemsPerMinute(0)); + + [Fact] + public void WorkingItemsPerMinuteForSpeedOne() => + Assert.Equal(3, AssemblyLine.WorkingItemsPerMinute(1)); + + [Fact] + public void WorkingItemsPerMinuteForSpeedFive() => + Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); + + [Fact] + public void WorkingItemsPerMinuteForSpeedFour() => + Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); + + [Fact] + public void WorkingItemsPerMinuteForSpeedTen() => + Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); +} \ No newline at end of file diff --git a/exercises/concept/strings/.docs/after.md b/exercises/concept/strings/.docs/after.md new file mode 100644 index 0000000000..a5354165a8 --- /dev/null +++ b/exercises/concept/strings/.docs/after.md @@ -0,0 +1,5 @@ +# After + +- The [advanced string interpolation tutorial][tutorial-docs.microsoft.com-string-interpolation] digs deeper into string interpolation. + +[tutorial-docs.microsoft.com-string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/strings/.docs/hints.md new file mode 100644 index 0000000000..1c5a2e9368 --- /dev/null +++ b/exercises/concept/strings/.docs/hints.md @@ -0,0 +1,27 @@ +# Hints + +### General + +- The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction C# `string`'s. +- The `string` class has many useful [built-in methods][docs-string-methods]. + +### 1. Get message from a log line + +- Different options to search for text in a string are explored in [this tutorial][tutorial-docs.microsoft.com-search-text-in-string]. +- Removing white space is [built-in][tutorial-docs.microsoft.com-trim-white-space]. + +### 2. Get log level from a log line + +- Changing a `string`'s casing is explored in [this tutorial][tutorial-docs.microsoft.com-changing-case]. + +### 3. Reformat a log line + +- There are several ways to [concatenate strings][tutorial-docs.microsoft.com-concatenate-strings], but the preferred one is usually [string interpolation][tutorial-csharp.net-string-interpolation]. + +[docs-string-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.0#methods +[tutorial-docs.microsoft.com-search-text-in-string]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/search-strings#where-does-the-sought-text-occur-in-a-string +[tutorial-docs.microsoft.com-trim-white-space]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/modify-string-contents#trim-white-space +[tutorial-docs.microsoft.com-changing-case]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/changing-case +[tutorial-docs.microsoft.com-concatenate-strings]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings +[tutorial-csharp.net-strings]: https://csharp.net-tutorials.com/data-types/strings/ +[tutorial-csharp.net-string-interpolation]: https://csharp.net-tutorials.com/operators/the-string-interpolation-operator/ diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md new file mode 100644 index 0000000000..4d53521267 --- /dev/null +++ b/exercises/concept/strings/.docs/instructions.md @@ -0,0 +1,47 @@ +# Instructions + +In this exercise you'll be processing log-lines. + +Each log line is a string formatted as follows: `"[]: "`. + +There are three different log levels: + +- `INFO` +- `WARNING` +- `ERROR` + +You have three tasks, each of which will take a log line and ask you to do something with it. + +### 1. Get message from a log line + +Implement a method to return a log line's message: + +```csharp +Strings.Message("[ERROR]: Invalid operation") +// Returns: "Invalid operation" +``` + +Any leading or trailing white space should be removed: + +```csharp +Strings.Message("[WARNING]: Disk almost full\r\n") +// Returns: "Disk almost full" +``` + +### 2. Get log level from a log line + +Implement a method to return a log line's log level, which should be returned in lowercase: + +```csharp +Strings.LogLevel("[ERROR]: Invalid operation") +// Returns: "error" +``` + +### 3. Reformat a log line + +Implement a method that reformats the log line, putting the message first and the log level after it in parentheses: + +```csharp +Strings.Reformat("[INFO]: Operation completed") +// Returns: "Operation completed (info)" +``` diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md new file mode 100644 index 0000000000..36b309245c --- /dev/null +++ b/exercises/concept/strings/.docs/introduction.md @@ -0,0 +1,3 @@ +# Introduction + +A `string` in C# is a sequence of Unicode characters (letters, digits, punctuation, etc.). diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs new file mode 100644 index 0000000000..faf1a56bf4 --- /dev/null +++ b/exercises/concept/strings/.meta/Example.cs @@ -0,0 +1,11 @@ +public static class LogLine +{ + public static string Message(string logLine) => + logLine.Substring(logLine.IndexOf(":") + 1).Trim(); + + public static string LogLevel(string logLine) => + logLine.Substring(1, logLine.IndexOf("]")).ToLower(); + + public static string Reformat(string logLine) => + $"{Message(logLine)} ({LogLevel(logLine)})"; +} \ No newline at end of file diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json new file mode 100644 index 0000000000..bb09573864 --- /dev/null +++ b/exercises/concept/strings/.meta/config.json @@ -0,0 +1,50 @@ +{ + "solution_files": ["Strings.cs"], + "test_file": "StringsTest.cs", + "tests": [ + { + "name": "ErrorMessage", + "cmd": "LogLine.Message(\"[ERROR]: Stack overflow\")" + }, + { + "name": "WarningMessage", + "cmd": "LogLine.Message(\"[WARNING]: Disk almost full\")" + }, + { + "name": "InfoMessage", + "cmd": "LogLine.Message(\"[INFO]: File moved\")" + }, + { + "name": "MessageWithLeadingAndTrailingWhiteSpace", + "cmd": "LogLine.Message(\"[WARNING]: \tTimezone not set \r\n\")" + }, + { + "name": "ErrorLogLevel", + "cmd": "LogLine.LogLevel(\"[ERROR]: Disk full\")" + }, + { + "name": "WarningLogLevel", + "cmd": "LogLine.LogLevel(\"[WARNING]: Unsafe password\")" + }, + { + "name": "InfoLogLevel", + "cmd": "LogLine.LogLevel(\"[INFO]: Timezone changed\")" + }, + { + "name": "ErrorReformat", + "cmd": "LogLine.Reformat(\"[ERROR]: Segmentation fault\")" + }, + { + "name": "WarningReformat", + "cmd": "LogLine.Reformat(\"[WARNING]: Decreased performance\")" + }, + { + "name": "InfoReformat", + "cmd": "LogLine.Reformat(\"[INFO]: Disk defragmented\")" + }, + { + "name": "ReformatWithLeadingAndTrailingWhiteSpace", + "cmd": "LogLine.Reformat(\"[ERROR]: \t Corrupt disk\t \t \r\n\")" + } + ] +} diff --git a/exercises/concept/strings/Strings.cs b/exercises/concept/strings/Strings.cs new file mode 100644 index 0000000000..f1fa861bb0 --- /dev/null +++ b/exercises/concept/strings/Strings.cs @@ -0,0 +1,19 @@ +using System; + +public static class LogLine +{ + public static string Message(string logLine) + { + throw new NotImplementedException("Please implement the LogLine.Message method"); + } + + public static string LogLevel(string logLine) + { + throw new NotImplementedException("Please implement the LogLine.LogLevel method"); + } + + public static string Reformat(string logLine) + { + throw new NotImplementedException("Please implement the LogLine.Reformat method"); + } +} \ No newline at end of file diff --git a/exercises/concept/strings/Strings.csproj b/exercises/concept/strings/Strings.csproj new file mode 100644 index 0000000000..e4ae56cdd6 --- /dev/null +++ b/exercises/concept/strings/Strings.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.0 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/strings/StringsTest.cs b/exercises/concept/strings/StringsTest.cs new file mode 100644 index 0000000000..4203add97e --- /dev/null +++ b/exercises/concept/strings/StringsTest.cs @@ -0,0 +1,48 @@ +using Xunit; + +public class LogLineTest +{ + [Fact] + public void ErrorMessage() => + Assert.Equal("Stack overflow", LogLine.Message("[ERROR]: Stack overflow")); + + [Fact] + public void WarningMessage() => + Assert.Equal("Disk almost full", LogLine.Message("[WARNING]: Disk almost full")); + + [Fact] + public void InfoMessage() => + Assert.Equal("File moved", LogLine.Message("[INFO]: File moved")); + + [Fact] + public void MessageWithLeadingAndTrailingWhiteSpace() => + Assert.Equal("Timezone not set", LogLine.Message("[WARNING]: \tTimezone not set \r\n")); + + [Fact] + public void ErrorLogLevel() => + Assert.Equal("error", LogLine.LogLevel("[ERROR]: Disk full")); + + [Fact] + public void WarningLogLevel() => + Assert.Equal("warning", LogLine.LogLevel("[WARNING]: Unsafe password")); + + [Fact] + public void InfoLogLevel() => + Assert.Equal("info", LogLine.LogLevel("[INFO]: Timezone changed")); + + [Fact] + public void ErrorReformat() => + Assert.Equal("Segmentation fault (error)", LogLine.Reformat("[ERROR]: Segmentation fault")); + + [Fact] + public void WarningReformat() => + Assert.Equal("Decreased performance (warning)", LogLine.Reformat("[WARNING]: Decreased performance")); + + [Fact] + public void InfoReformat() => + Assert.Equal("Disk defragmented (info)", LogLine.Reformat("[INFO]: Disk defragmented")); + + [Fact] + public void ReformatWithLeadingAndTrailingWhiteSpace() => + Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); +} \ No newline at end of file diff --git a/reference/code_style.md b/reference/code_style.md new file mode 100644 index 0000000000..eb2e1d2096 --- /dev/null +++ b/reference/code_style.md @@ -0,0 +1,49 @@ +# Code style + +While the C# compiler doesn't enforce a particular code style, there are general [coding conventions][docs.microsoft.com_coding-conventions] and [design guidelines][docs.microsoft.com_design-guidelines]. + +## Formatting conventions + +The C# formatting formatting conventions are defined in the [layout conventions][docs.microsoft.com_layout-conventions]. + +## Naming conventions + +Broadly speaking, the C# naming conventions are as follows: + +- PascalCase for types, methods and constants. +- camelCase for fields, variables and parameters. + +These conventions are described in the [.NET capitalization conventions][docs.microsoft.com_capitalization-conventions] and the [.NET general naming conventions][docs.microsoft.com_general-naming-conventions]. + +## Other conventions + +### Prefer type alias + +The general consensus is to prefer the C# type over the .NET type. Here are some examples where this prefererence shows: + +- The default [C# editorconfig settings][docs.microsoft.com_editorconfig-language-keywords]. +- The [ReSharper built-in type naming rule][jetbrains.com_built-in-type-naming]. +- The [CoreFX coding style document][github.com_corefx-coding-style]. + +## Enforcing code style + +It is possible to encode C# coding style conventions using [`.editorconfig files`][docs.microsoft.com_editorconfig]. This includes being able to specify [formatting conventions][docs.microsoft.com_editorconfig-formatting-conventions] and [naming conventions][docs.microsoft.com_editorconfig-naming-conventions]. + +Most C# IDE's have support for `.editorconfig` files, including Visual Studio 2019+, Rider and VS Code (using the C# extension). + +The [dotnet format global tool][github.com_dotnet-format-editorconfig-options] can be run as a [command-line tool][github.com_dotnet-format-how-to] and has support for a [limited set of the `.editorconfig` settings][github.com_dotnet-format-editorconfig-options]. + +[docs.microsoft.com_design-guidelines]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/ +[docs.microsoft.com_coding-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions +[docs.microsoft.com_capitalization-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions +[docs.microsoft.com_general-naming-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions +[docs.microsoft.com_layout-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions#layout-conventions +[docs.microsoft.com_editorconfig]: https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2019 +[docs.microsoft.com_editorconfig-formatting-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions?view=vs-2019 +[docs.microsoft.com_editorconfig-naming-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions?view=vs-2019 +[github.com_dotnet-format]: https://github.com/dotnet/format/blob/master/README.md +[github.com_dotnet-format-editorconfig-options]: https://github.com/dotnet/format/wiki/Supported-.editorconfig-options +[github.com_dotnet-format-how-to]: https://github.com/dotnet/format/blob/master/README.md#how-to-install +[docs.microsoft.com_editorconfig-language-keywords]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#language-keywords +[github.com_corefx-coding-style]: https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md +[jetbrains.com_built-in-type-naming]: https://www.jetbrains.com/help/resharper/Built_In_Type_Naming.html diff --git a/reference/memory_allocation.md b/reference/memory_allocation.md new file mode 100644 index 0000000000..81e4fbe7f4 --- /dev/null +++ b/reference/memory_allocation.md @@ -0,0 +1,28 @@ +# Memory allocation + +The important thing about allocating memory in C# is that it is done _automatically_; there is no need to manually allocate memory. To allow the automatic memory to also be deallocated when it is no longer used, C# uses a [garbage collector][docs.microsoft.com_garbage-collection-fundamentals]. + +There are two different types of memory used when working with C#: + +- The stack. +- The heap. + +The stack is short-lived and has limited space available. Exceeding the maximum amount of allowed memory of the stack results in a `StackOverflowException` being thrown. Each thread has its own stack. As the stack is automatically "unwinded" after a method returns, there is no need for the garbage collector to be involved. This means that (de)allocating memory on the stack is very fast. + +The heap is long-lived and has lots of memory available. When an object is allocated, the memory allocator will find some free memory on the heap and allocate it. The heap is shared between threads and can be used to share data. Once every while, the garbage collector will halt execution (a "GC pause") and check if there are objects that are no longer being used. If so, the memory for these objects will be deallocated and their memory will become available for later allocation again. + +## What goes where? + +In principle, value types are allocated on the stack and reference types on the heap. There are some exceptions to this, for example when a value type is part of a reference type (e.g. a class with an `int` field). + +## Resources + +- [Garbage collection fundamentals][docs.microsoft.com_garbage-collection-fundamentals] +- [Jetbrains memory management concepts][jetbrains.com_memory-management-concepts] +- [Jon skeet on C# memory allocation][jonskeet.uk_memory] +- [Pro .NET memory management (book)][pro-dotnet-memory] + +[docs.microsoft.com_garbage-collection-fundamentals]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals +[jonskeet.uk_memory]: https://jonskeet.uk/csharp/memory.html +[jetbrains.com_memory-management-concepts]: https://www.jetbrains.com/help/dotmemory/NET_Memory_Management_Concepts.html +[pro-dotnet-memory]: https://prodotnetmemory.com/ From 091cf391c6a92115d3445669a990e9d46ccfa411 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 Jan 2020 09:01:03 +0100 Subject: [PATCH 004/327] Shared docs docs: move shared documents to exercises/shared/.docs --- exercises/shared/.docs/cli.md | 13 +++++++++++++ exercises/shared/.docs/debug.md | 10 ++++++++++ 2 files changed, 23 insertions(+) create mode 100644 exercises/shared/.docs/cli.md create mode 100644 exercises/shared/.docs/debug.md diff --git a/exercises/shared/.docs/cli.md b/exercises/shared/.docs/cli.md new file mode 100644 index 0000000000..ecfd8e1c6b --- /dev/null +++ b/exercises/shared/.docs/cli.md @@ -0,0 +1,13 @@ +# CLI + +You can run the tests by opening a command prompt in the exercise's directory, and then running the [`dotnet test` command][docs-dotnet-test]. Alternatively, most IDE's have built-in support for running tests, including [Visual Studio][docs-run-unit-tests-visual-studio], [Rider][docs-run-unit-tests-rider] and [Visual Studio code][docs-run-unit-tests-visual-studio-code]. + +Initially, only the first test will be enabled. This is to encourage you to solve the exercise one step at a time. Once you get the first test passing, remove the `Skip` property from the next test and work on getting that test passing. + +Once none of the tests are skipped and they are all passing, you can submit your solution by opening a command prompt in the exercise's directory and running the [`exercism submit` command][docs-exercism-cli]. + +[docs-dotnet-test]: https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-test?tabs=netcore21 +[docs-exercism-cli]: https://exercism.io/cli +[docs-run-unit-tests-visual-studio]: https://docs.microsoft.com/en-us/visualstudio/test/run-unit-tests-with-test-explorer?view=vs-2019 +[docs-run-unit-tests-visual-studio-code]: https://github.com/OmniSharp/omnisharp-vscode/wiki/How-to-run-and-debug-unit-tests +[docs-run-unit-tests-rider]: https://www.jetbrains.com/help/rider/Unit_Testing_in_Solution.html diff --git a/exercises/shared/.docs/debug.md b/exercises/shared/.docs/debug.md new file mode 100644 index 0000000000..8be437efc1 --- /dev/null +++ b/exercises/shared/.docs/debug.md @@ -0,0 +1,10 @@ +# Debug + +When a test fails, a message is displayed describing what went wrong and for which input. You can also use the fact that any [console output][programiz.com-basic-input-output] will be shown too. You can write to the console using: + +```csharp +Console.WriteLine("Debug message"); +``` + +[docs-string]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/ +[programiz.com-basic-input-output]: https://www.programiz.com/csharp-programming/basic-input-output From a7998dde5bb5da7abc9cdf1885f90d116ef58101 Mon Sep 17 00:00:00 2001 From: wolf99 Date: Thu, 16 Jan 2020 20:48:39 +0000 Subject: [PATCH 005/327] Correct broken link dot net lang documentation was consolidated to a central `dotnet` repository --- reference/code_style.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/code_style.md b/reference/code_style.md index eb2e1d2096..59ad5be88d 100644 --- a/reference/code_style.md +++ b/reference/code_style.md @@ -45,5 +45,5 @@ The [dotnet format global tool][github.com_dotnet-format-editorconfig-options] c [github.com_dotnet-format-editorconfig-options]: https://github.com/dotnet/format/wiki/Supported-.editorconfig-options [github.com_dotnet-format-how-to]: https://github.com/dotnet/format/blob/master/README.md#how-to-install [docs.microsoft.com_editorconfig-language-keywords]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#language-keywords -[github.com_corefx-coding-style]: https://github.com/dotnet/corefx/blob/master/Documentation/coding-guidelines/coding-style.md +[github.com_corefx-coding-style]: https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md [jetbrains.com_built-in-type-naming]: https://www.jetbrains.com/help/resharper/Built_In_Type_Naming.html From 5a3f580be43891f08b82a9cd62df90fed6df76aa Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 17 Jan 2020 13:25:52 +0100 Subject: [PATCH 006/327] Introduce looping in introduction of numbers-floating-point exercise Introduce looping in introduction --- exercises/concept/numbers-floating-point/.docs/hints.md | 2 +- exercises/concept/numbers-floating-point/.docs/introduction.md | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/numbers-floating-point/.docs/hints.md index 6e5e807dc7..f4448a5e71 100644 --- a/exercises/concept/numbers-floating-point/.docs/hints.md +++ b/exercises/concept/numbers-floating-point/.docs/hints.md @@ -14,7 +14,7 @@ ### 3. Calculate the years before reaching the desired balance -- To calculate the years, one has to loop over the balance. C# has several [looping constructs][docs.microsoft.com-loops]. +- To calculate the years, one can keep looping until the desired balance is reached. C# has several [looping constructs][docs.microsoft.com-loops]. [docs-microsoft.com-system.math]: https://docs.microsoft.com/en-us/dotnet/api/system.math?view=netcore-3.0 [docs.microsoft.com-floating_point_numeric_types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/numbers-floating-point/.docs/introduction.md index 50e6c0da55..a77ccf10c3 100644 --- a/exercises/concept/numbers-floating-point/.docs/introduction.md +++ b/exercises/concept/numbers-floating-point/.docs/introduction.md @@ -11,3 +11,5 @@ C# has three floating point types: - `decimal`: 16 bytes (28-29 digits precision). Normally used when working with monetary data, as its precision leads to less rounding errors. Written as `2.45m`. As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded). + +In this exercise you may also want to use a loop. There are several ways to write loops in C#, the most common ones being `while` and `for` loops. From db921a045f150126497a34412ffa786ddfc55993 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 24 Jan 2020 10:03:50 +0100 Subject: [PATCH 007/327] Fix rounding error in numbers exercise --- exercises/concept/numbers/.meta/Example.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index cdd919471e..49a755b467 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -9,7 +9,7 @@ private static int ProductionRatePerHourForSpeed(int speed) => ProductionRatePerHourForDefaultSpeed * speed; public static int WorkingItemsPerMinute(int speed) => - (int)ProductionRatePerHour(speed) / 60; + (int)(ProductionRatePerHour(speed) / 60); private static double SuccessRate(int speed) { From c1a98a1a13a867a626fc76ac1cb84cea02955b11 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 27 Jan 2020 20:39:23 +0000 Subject: [PATCH 008/327] Remove .meta/config.json file --- .../bitwise-operations/.meta/config.json | 94 ---------------- exercises/concept/dates/.meta/config.json | 102 ------------------ exercises/concept/enums/.meta/config.json | 38 ------- .../numbers-floating-point/.meta/config.json | 102 ------------------ exercises/concept/numbers/.meta/config.json | 46 -------- exercises/concept/strings/.meta/config.json | 50 --------- 6 files changed, 432 deletions(-) delete mode 100644 exercises/concept/bitwise-operations/.meta/config.json delete mode 100644 exercises/concept/dates/.meta/config.json delete mode 100644 exercises/concept/enums/.meta/config.json delete mode 100644 exercises/concept/numbers-floating-point/.meta/config.json delete mode 100644 exercises/concept/numbers/.meta/config.json delete mode 100644 exercises/concept/strings/.meta/config.json diff --git a/exercises/concept/bitwise-operations/.meta/config.json b/exercises/concept/bitwise-operations/.meta/config.json deleted file mode 100644 index 9e648d5259..0000000000 --- a/exercises/concept/bitwise-operations/.meta/config.json +++ /dev/null @@ -1,94 +0,0 @@ -{ - "solution_files": ["BitwiseOperations.cs"], - "test_file": "BitwiseOperationsTest.cs", - "tests": [ - { - "name": "DefaultForGuest", - "cmd": "Permissions.Default(AccountType.Guest)" - }, - { - "name": "DefaultForUser", - "cmd": "Permissions.Default(AccountType.User)" - }, - { - "name": "DefaultForModerator", - "cmd": "Permissions.Default(AccountType.Moderator)" - }, - { - "name": "DefaultForUnknown", - "cmd": "Permissions.Default((AccountType)123)" - }, - { - "name": "GrantReadToNone", - "cmd": "Permissions.Grant(Permission.None, Permission.Read)" - }, - { - "name": "GrantReadToRead", - "cmd": "Permissions.Grant(Permission.Read, Permission.Read)" - }, - { - "name": "GrantAllToNone", - "cmd": "Permissions.Grant(Permission.None, Permission.All)" - }, - { - "name": "GrantDeleteToReadAndWrite", - "cmd": "Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)" - }, - { - "name": "GrantReadAndWriteToNone", - "cmd": "Permissions.Grant(Permission.None, Permission.Read | Permission.Write)" - }, - { - "name": "RevokeNoneFromRead", - "cmd": "Permissions.Revoke(Permission.Read, Permission.None)" - }, - { - "name": "RevokeWriteFromWrite", - "cmd": "Permissions.Revoke(Permission.Write, Permission.Write)" - }, - { - "name": "RevokeDeleteFromAll", - "cmd": "Permissions.Revoke(Permission.All, Permission.Delete)" - }, - { - "name": "RevokeReadAndWriteFromWriteAndDelete", - "cmd": "Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)" - }, - { - "name": "RevokeAllFromReadAndWrite", - "cmd": "Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)" - }, - { - "name": "CheckNoneForRead", - "cmd": "Permissions.Check(Permission.None, Permission.Read)" - }, - { - "name": "CheckWriteForWrite", - "cmd": "Permissions.Check(Permission.Write, Permission.Write)" - }, - { - "name": "CheckAllForWrite", - "cmd": "Permissions.Check(Permission.All, Permission.Write)" - }, - { - "name": "CheckReadAndWriteForRead", - "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read)" - }, - { - "name": "CheckAllForReadAndWrite", - "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)" - }, - { - "name": "CheckReadAndWriteForReadAndWrite", - "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)" - }, - { - "name": "CheckReadAndWriteForReadAndDelete", - "cmd": "Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)" - }, - { - "name": "CheckReadAndWriteAndDeleteForAll", - "cmd": "Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)" - } - ] -} diff --git a/exercises/concept/dates/.meta/config.json b/exercises/concept/dates/.meta/config.json deleted file mode 100644 index 56c5c4637b..0000000000 --- a/exercises/concept/dates/.meta/config.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "solution_files": ["Dates.cs"], - "test_file": "DatesTest.cs", - "tests": [ - { - "name": "ScheduleDateUsingOnlyNumbers", - "cmd": "Appointment.Schedule(\"7/25/2019 13:45:00\")" - }, - { - "name": "ScheduleDateWithTextualMonth", - "cmd": "Appointment.Schedule(\"June 3, 2019 11:30:00\")" - }, - { - "name": "ScheduleDateWithTextualMonthAndWeekday", - "cmd": "Appointment.Schedule(\"Thursday, December 5, 2019 09:00:00\")" - }, - { - "name": "HasPassedWithAppointmentOneYearAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))" - }, - { - "name": "HasPassedWithAppointmentMonthsAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMonths(-8))" - }, - { - "name": "HasPassedWithAppointmentDaysAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddDays(-23))" - }, - { - "name": "HasPassedWithAppointmentHoursAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddHours(-12))" - }, - { - "name": "HasPassedWithAppointmentMinutesAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(-55))" - }, - { - "name": "HasPassedWithAppointmentOneMinuteAgo", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(-1))" - }, - { - "name": "HasPassedWithAppointmentInOneMinute", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(1))" - }, - { - "name": "HasPassedWithAppointmentInMinutes", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMinutes(5))" - }, - { - "name": "HasPassedWithAppointmentInDays", - "cmd": "Appointment.HasPassed(DateTime.Now.AddDays(19))" - }, - { - "name": "HasPassedWithAppointmentInMonths", - "cmd": "Appointment.HasPassed(DateTime.Now.AddMonths(10))" - }, - { - "name": "HasPassedWithAppointmentInYears", - "cmd": "Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))" - }, - { - "name": "IsAfternoonAppointmentForEarlyMorningAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))" - }, - { - "name": "IsAfternoonAppointmentForLateMorningAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))" - }, - { - "name": "IsAfternoonAppointmentForNoonAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))" - }, - { - "name": "IsAfternoonAppointmentForEarlyAfternoonAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))" - }, - { - "name": "IsAfternoonAppointmentForLateAfternoonAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))" - }, - { - "name": "IsAfternoonAppointmentForEarlyEveningAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))" - }, - { - "name": "IsAfternoonAppointmentForLateEveningAppointment", - "cmd": "Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))" - }, - { - "name": "DescriptionOnFridayAfternoon", - "cmd": "Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))" - }, - { - "name": "DescriptionOnThursdayAfternoon", - "cmd": "Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))" - }, - { - "name": "DescriptionOnWednesdayMorning", - "cmd": "Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))" - } - ] -} diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/enums/.meta/config.json deleted file mode 100644 index e6378f8d6f..0000000000 --- a/exercises/concept/enums/.meta/config.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "solution_files": ["Enums.cs"], - "test_file": "EnumsTest.cs", - "tests": [ - { - "name": "ParseError", - "cmd": "LogLine.ParseLogLevel(\"[ERROR]: Disk full\")" - }, - { - "name": "ParseWarning", - "cmd": "LogLine.ParseLogLevel(\"[WARNING]: Timezone not set\")" - }, - { - "name": "ParseInfo", - "cmd": "LogLine.ParseLogLevel(\"[INFO]: Timezone changed\")" - }, - { - "name": "ParseUnknown", - "cmd": "LogLine.ParseLogLevel(\"[FATAL]: Crash!\")" - }, - { - "name": "OutputForShortLogForError", - "cmd": "LogLine.OutputForShortLog(LogLevel.Error, \"Stack overflow\")" - }, - { - "name": "OutputForShortLogForWarning", - "cmd": "LogLine.OutputForShortLog(LogLevel.Warning, \"Unsafe password\")" - }, - { - "name": "OutputForShortLogForInfo", - "cmd": "LogLine.OutputForShortLog(LogLevel.Info, \"File moved\")" - }, - { - "name": "OutputForShortLogForUnknown", - "cmd": "LogLine.OutputForShortLog(LogLevel.Unknown, \"Something unknown happened\")" - } - ] -} diff --git a/exercises/concept/numbers-floating-point/.meta/config.json b/exercises/concept/numbers-floating-point/.meta/config.json deleted file mode 100644 index af3aeb01ed..0000000000 --- a/exercises/concept/numbers-floating-point/.meta/config.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "solution_files": ["NumbersFloatingPoint.cs"], - "test_file": "NumbersFloatingPointTest.cs", - "tests": [ - { - "name": "MinimalFirstAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(0m)" - }, - { - "name": "TinyFirstAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(0.000001m)" - }, - { - "name": "MaximumFirstAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(999.9999m)" - }, - { - "name": "MinimalSecondAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(1_000.0m)" - }, - { - "name": "TinySecondAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(1_000.0001m)" - }, - { - "name": "MaximumSecondAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(4_999.9990m)" - }, - { - "name": "MinimalThirdAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(5_000.0000m)" - }, - { - "name": "TinyThirdAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(5_000.0001m)" - }, - { - "name": "LargeThirdAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(5_639_998.742909m)" - }, - { - "name": "MinimalNegativeAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(-0.000001m)" - }, - { - "name": "SmallNegativeAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(-0.123m)" - }, - { - "name": "RegularNegativeAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(-300.0m)" - }, - { - "name": "LargeNegativeAnnualPercentageYield", - "cmd": "SavingsAccount.AnnualPercentageYield(-152964.231m)" - }, - { - "name": "AnnualBalanceUpdateForEmptyStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(0.0m)" - }, - { - "name": "AnnualBalanceUpdateForSmallPositiveStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(0.000001m)" - }, - { - "name": "AnnualBalanceUpdateForAveragePositiveStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(1_000.0m)" - }, - { - "name": "AnnualBalanceUpdateForLargePositiveStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(1_000.0001m)" - }, - { - "name": "AnnualBalanceUpdateForHugePositiveStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)" - }, - { - "name": "AnnualBalanceUpdateForSmallNegativeStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(-0.123m)" - }, - { - "name": "AnnualBalanceUpdateForLargeNegativeStartBalance", - "cmd": "SavingsAccount.AnnualBalanceUpdate(-152964.231m)" - }, - { - "name": "YearsBeforeDesiredBalanceForSmallStartBalance", - "cmd": "SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)" - }, - { - "name": "YearsBeforeDesiredBalanceForAverageStartBalance", - "cmd": "SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)" - }, - { - "name": "YearsBeforeDesiredBalanceForLargeStartBalance", - "cmd": "SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)" - }, - { - "name": "YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance", - "cmd": "SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)" - } - ] -} diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json deleted file mode 100644 index 5579d4392a..0000000000 --- a/exercises/concept/numbers/.meta/config.json +++ /dev/null @@ -1,46 +0,0 @@ -{ - "solution_files": ["Numbers.cs"], - "test_file": "NumbersTest.cs", - "tests": [ - { - "name": "ProductionRatePerHourForSpeedZero", - "cmd": "AssemblyLine.ProductionRatePerHour(0)" - }, - { - "name": "ProductionRatePerHourForSpeedOne", - "cmd": "AssemblyLine.ProductionRatePerHour(1)" - }, - { - "name": "ProductionRatePerHourForSpeedFour", - "cmd": "AssemblyLine.ProductionRatePerHour(4)" - }, - { - "name": "ProductionRatePerHourForSpeedSeven", - "cmd": "AssemblyLine.ProductionRatePerHour(7)" - }, - { - "name": "ProductionRatePerHourForSpeedNine", - "cmd": "AssemblyLine.ProductionRatePerHour(9)" - }, - { - "name": "WorkingItemsPerMinuteForSpeedZero", - "cmd": "AssemblyLine.WorkingItemsPerMinute(0)" - }, - { - "name": "WorkingItemsPerMinuteForSpeedOne", - "cmd": "AssemblyLine.WorkingItemsPerMinute(1)" - }, - { - "name": "WorkingItemsPerMinuteForSpeedFive", - "cmd": "AssemblyLine.WorkingItemsPerMinute(5)" - }, - { - "name": "WorkingItemsPerMinuteForSpeedFour", - "cmd": "AssemblyLine.WorkingItemsPerMinute(8)" - }, - { - "name": "WorkingItemsPerMinuteForSpeedTen", - "cmd": "AssemblyLine.WorkingItemsPerMinute(10)" - } - ] -} diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json deleted file mode 100644 index bb09573864..0000000000 --- a/exercises/concept/strings/.meta/config.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "solution_files": ["Strings.cs"], - "test_file": "StringsTest.cs", - "tests": [ - { - "name": "ErrorMessage", - "cmd": "LogLine.Message(\"[ERROR]: Stack overflow\")" - }, - { - "name": "WarningMessage", - "cmd": "LogLine.Message(\"[WARNING]: Disk almost full\")" - }, - { - "name": "InfoMessage", - "cmd": "LogLine.Message(\"[INFO]: File moved\")" - }, - { - "name": "MessageWithLeadingAndTrailingWhiteSpace", - "cmd": "LogLine.Message(\"[WARNING]: \tTimezone not set \r\n\")" - }, - { - "name": "ErrorLogLevel", - "cmd": "LogLine.LogLevel(\"[ERROR]: Disk full\")" - }, - { - "name": "WarningLogLevel", - "cmd": "LogLine.LogLevel(\"[WARNING]: Unsafe password\")" - }, - { - "name": "InfoLogLevel", - "cmd": "LogLine.LogLevel(\"[INFO]: Timezone changed\")" - }, - { - "name": "ErrorReformat", - "cmd": "LogLine.Reformat(\"[ERROR]: Segmentation fault\")" - }, - { - "name": "WarningReformat", - "cmd": "LogLine.Reformat(\"[WARNING]: Decreased performance\")" - }, - { - "name": "InfoReformat", - "cmd": "LogLine.Reformat(\"[INFO]: Disk defragmented\")" - }, - { - "name": "ReformatWithLeadingAndTrailingWhiteSpace", - "cmd": "LogLine.Reformat(\"[ERROR]: \t Corrupt disk\t \t \r\n\")" - } - ] -} From bac66c39a22c3634e492a3e34265b15a6c4a7545 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 27 Jan 2020 20:42:34 +0000 Subject: [PATCH 009/327] Add Float Toy link to after for numbers-floating-point exercise --- exercises/concept/numbers-floating-point/.docs/after.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md index 67d326f0e8..357316236e 100644 --- a/exercises/concept/numbers-floating-point/.docs/after.md +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -8,8 +8,11 @@ - You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. +- The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. + [docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions [docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions [docs-microsoft.com-characteristics-of-the-floating-point-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types [docs.microsoft.com_precision-in-comparisons]: https://docs.microsoft.com/en-us/dotnet/api/system.double.equals#precision-in-comparisons [0.30000000000000004.com]: https://0.30000000000000004.com/ +[evanw.github.io-float-toy]: https://evanw.github.io/float-toy/ From fae9bd07c1d7b1de9239f42c9ae7deffd3c128b9 Mon Sep 17 00:00:00 2001 From: Rob Keim Date: Sun, 26 Jan 2020 19:24:44 +0100 Subject: [PATCH 010/327] Extract concepts of v2 book-store exercise --- reference/exercise-concepts/book-store.md | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 reference/exercise-concepts/book-store.md diff --git a/reference/exercise-concepts/book-store.md b/reference/exercise-concepts/book-store.md new file mode 100644 index 0000000000..84c681e11d --- /dev/null +++ b/reference/exercise-concepts/book-store.md @@ -0,0 +1,33 @@ +# Concepts of book-store + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/book-store/Example.cs) + +## General + +- functions: used as the main entry point for the exercise and used for sub functions in order to break the solution down into smaller chunks +- function arguments: books are passed as an argument +- return values: returning a value from a method +- conditionals using if: conditionally execute logic using an `if` statement +- scoping: use `{` and `}` to denote scoping +- classes: the tested method is defined in a class +- members: methods linked to a class instance +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `Linq` methods +- type inference: using `var` to define complex types +- assignment: assigning values +- immutability: defining the base book price as a `const` +- equality operator: `==` +- ordering operators: `>` +- math operators: `+`, `*`, `-` are used +- enumerables: arrays can can be iterated over as an enumerable (using Linq) +- floating point numbers: a `decimal` is used for calculating the total price +- arrays: an `int[]` is used as an input parameter to the main method +- math standard library: use of `Math.Round` and `Math.Min` +- mapping, selecting, ordering enumerables: using multiple Linq methods to manipulate enumerables (`Concat`, `GroupBy`, `Min`, `OrderByDescending`, `Select`, `Take`, `ToArray`, `Where`) + +## Switch for discount percentage +- switch: used to map the discount percentage based on the number of unique books + +## Dictionary for discount percentages +- dictionaries: `Dictionary` for mapping the discount percentage based on the number of unique books \ No newline at end of file From f59415f9d2285a7dd3c496bf9f91464750525b28 Mon Sep 17 00:00:00 2001 From: Brandon Everett Date: Wed, 29 Jan 2020 05:29:10 -0500 Subject: [PATCH 011/327] extract concepts of v2 robot-name exercise extract concepts of v2 robot-name exercise --- reference/exercise-concepts/robot-name.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 reference/exercise-concepts/robot-name.md diff --git a/reference/exercise-concepts/robot-name.md b/reference/exercise-concepts/robot-name.md new file mode 100644 index 0000000000..a1a2d1ccfa --- /dev/null +++ b/reference/exercise-concepts/robot-name.md @@ -0,0 +1,21 @@ +# Concepts of Robot Name + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/robot-name/Example.cs) + +## General +- functions: used as the main entry point to this exercise +- constructors: initalizing values when object is created +- conditionals using if: conditionally execute logic using an `if` statement +- classes: the tested method is defined in a class +- objects: creating an object to keep track of the robot +- state: keeping track of the names +- members: methods linked to a class instance +- static variables: keeping state across class instances +- hashSet: test suite uses hash set to ensure name is unique +- random numbers: using the built in `Random` class +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `HashSet` class +- do while loop: loop to find valid names +- regex: test suite uses regex to test valid names + From e8147027a74fcae9710ccbee78e2822445619fd0 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 29 Jan 2020 12:50:31 +0000 Subject: [PATCH 012/327] Extract concepts of v2 nucleotide-count exercise Extract concepts of v2 nucleotide-count exercise Co-Authored-By: Rob Keim --- .../exercise-concepts/nucleotide-count.md | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 reference/exercise-concepts/nucleotide-count.md diff --git a/reference/exercise-concepts/nucleotide-count.md b/reference/exercise-concepts/nucleotide-count.md new file mode 100644 index 0000000000..90e51bc0fa --- /dev/null +++ b/reference/exercise-concepts/nucleotide-count.md @@ -0,0 +1,49 @@ +# Concepts of nucleotide-count + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/nucleotide-count/Example.cs) + +## General + +- functions: used as the main entry point for the exercise +- function arguments: input strand is passed as an argument +- return values: returning a value from a method +- conditionals using if: conditionally execute logic using an `if` statement +- exceptions: throw an exception in the event of invalid input +- scoping: use `{` and `}` to denote scoping +- interfaces: the type returned is an `IDictionary` +- classes: the tested method is defined in a class +- objects: creating an instance of the `Dictionary` class +- static: the tested method is a static method +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `Dictionary` class +- type inference: using `var` to define variable for dictionary +- assignment: assigning values, such as the dictionary +- mutation: mutating the dictionary after it has been created +- math operators: `+` or `++` operator to increment count +- strings: a `string` passed as the single input parameter +- characters: a `char` is used as key in the dictionary that is returned +- integers: an `int` is used as value in the dictionary that is returned +- dictionaries: a `Dictionary` is used as return value + +## Approach: foreach loop + +- foreach loop: iterate over letters using a `foreach` loop +- enumerables: a `string` can be iterated over as an enumerable + +## Approach: for loop + +- for loop: iterate over letters using a `for` loop +- indexers: accessing a single `char` of a `string` using an indexer + +## Approach: object initializer for dictionary + +- object initializers: initializing dictionary through object initializer + +## Approach: using TryGetValue + +- out parameters: capturing the value as an `out` parameter + +## Notes + +- Having the exercise return an `IDictionary` means that the users will have to know about interfaces too. This was not the goal of the exercise (teaching about dictionaries is), so it's interesting to see that this was missed. Good thing to keep in mind when developing Concept Exercises. From ac1422d4645362bdb7fc6dfd3957dfe2322c4375 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 29 Jan 2020 14:48:18 +0000 Subject: [PATCH 013/327] Extract concepts of v2 bowling exercise Extract concepts of v2 bowling exercise --- reference/exercise-concepts/bowling.md | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 reference/exercise-concepts/bowling.md diff --git a/reference/exercise-concepts/bowling.md b/reference/exercise-concepts/bowling.md new file mode 100644 index 0000000000..3f06d69126 --- /dev/null +++ b/reference/exercise-concepts/bowling.md @@ -0,0 +1,37 @@ +# Concepts of bowling + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/bowling/Example.cs) + +## General + +- functions: used as the main entry point for the exercise +- function arguments: input strand is passed as an arguments +- return values: returning a value from a method +- conditionals using if: conditionally execute logic using an `if` statement +- exceptions: throw an exception in the event of invalid input +- scoping: use `{` and `}` to denote scoping +- classes: the tested method is defined in a class +- objects: creating an object to keep track of the rolls +- state: keeping track of the rolls +- members: methods linked to a class instance +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `List` class +- type inference: using `var` to define the score +- assignment: assigning values, such as the score +- mutation: mutating the list after it has been created +- immutability: defining the max score and number of frames as `const` and the list as `readonly` +- equality operator: `==`, `!=` +- ordering operators:`<`, `>`, `<=`, `>=` +- math operators: `+`, `%`, `+=` are used +- indexers: accessing a single `int` of the rolls +- enumerables: lists can can be iterated over as an enumerable +- for loop: iterate over rolls using a `for` loop +- integers: an `int` is used for rolls +- booleans: a `bool` is used in helper methods +- lists: a `List` is used as to store the rolls in +- nullable values: a `int?` is uses as the return value + +## Note + +- The return value should not be an `int?`, as this is still a remnant of an older version of the exercise. The latest version uses exceptions for all error cases, and should thus return a regular `int`. From 7b47f6c56b70b7cd94b6b50204cb224d2ffe2aaa Mon Sep 17 00:00:00 2001 From: Rob Keim Date: Wed, 29 Jan 2020 16:10:27 +0100 Subject: [PATCH 014/327] Add concepts for protein-translation exercise * Add concepts for protein-translation exercise * Update languages/reference/exercise-concepts/protein-translation.md Co-Authored-By: Erik Schierboom * Update languages/reference/exercise-concepts/protein-translation.md Co-Authored-By: Erik Schierboom * Add alternative approach using a dictionary to store the mapping Co-authored-by: Erik Schierboom --- .../exercise-concepts/protein-translation.md | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 reference/exercise-concepts/protein-translation.md diff --git a/reference/exercise-concepts/protein-translation.md b/reference/exercise-concepts/protein-translation.md new file mode 100644 index 0000000000..fcaa0516cc --- /dev/null +++ b/reference/exercise-concepts/protein-translation.md @@ -0,0 +1,30 @@ +# Concepts of protein-translation + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/protein-translation/Example.cs) + +## General + +- using keyword: for importing libraries +- access modifiers: in order to specify public vs private functions +- static keyword: in order to class/methods accessible without having to instantiate the class +- arrays: for the return value from the main function +- functions: used as the main entry point for the exercise +- function arguments: input strand is passed as an arguments +- var keyword: in order to prevent verbose declarations `List results = new List()` +- assignment: setting a variable to a specific value +- new keyword: used to instantiate a class +- lists: a `List` temporarily holds the results before converting them to an array (Add and ToArray methods) +- for loop: iterate through the strands +- integers: `int` type used as a counter in the loop +- math operations: <, *, and ++ +- strings: substring and comparison +- exceptions: throw an exception in the event of invalid input + +## Using a switch for mapping the proteins + +- switch cases: to convert the string to a protein name (including default case) + +## Using a dictionary for mapping the proteins + +- dictionaries: `Dictionary` is used to store a mapping +- immutable data structures: `ReadonlyDictionary` should be used for the mapping which never changes \ No newline at end of file From 2cfcd52fa937cdd8965989b2ef525c7dee0a0315 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 29 Jan 2020 17:24:24 +0000 Subject: [PATCH 015/327] Convert bitwise operations exercise to advanced enums exercise * Convert bitwise operations exercise to advanced enums exercise * add back link * Add extra docs * Update sidebar with links to design documents * Add dummy design.md documents * Link to design documents --- .../concept/bitwise-operations/.docs/after.md | 5 -- exercises/concept/dates/.meta/design.md | 33 +++++++++ .../concept/enums-advanced/.docs/after.md | 7 ++ .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../concept/enums-advanced/.meta/design.md | 69 +++++++++++++++++++ .../EnumsAdvanced.cs} | 0 .../EnumsAdvanced.csproj} | 0 .../EnumsAdvancedTest.cs} | 0 exercises/concept/enums/.meta/design.md | 33 +++++++++ .../numbers-floating-point/.meta/design.md | 33 +++++++++ exercises/concept/numbers/.meta/design.md | 33 +++++++++ exercises/concept/strings/.meta/design.md | 33 +++++++++ 15 files changed, 241 insertions(+), 5 deletions(-) delete mode 100644 exercises/concept/bitwise-operations/.docs/after.md create mode 100644 exercises/concept/dates/.meta/design.md create mode 100644 exercises/concept/enums-advanced/.docs/after.md rename exercises/concept/{bitwise-operations => enums-advanced}/.docs/hints.md (100%) rename exercises/concept/{bitwise-operations => enums-advanced}/.docs/instructions.md (100%) rename exercises/concept/{bitwise-operations => enums-advanced}/.docs/introduction.md (100%) rename exercises/concept/{bitwise-operations => enums-advanced}/.meta/Example.cs (100%) create mode 100644 exercises/concept/enums-advanced/.meta/design.md rename exercises/concept/{bitwise-operations/BitwiseOperations.cs => enums-advanced/EnumsAdvanced.cs} (100%) rename exercises/concept/{bitwise-operations/BitwiseOperations.csproj => enums-advanced/EnumsAdvanced.csproj} (100%) rename exercises/concept/{bitwise-operations/BitwiseOperationsTest.cs => enums-advanced/EnumsAdvancedTest.cs} (100%) create mode 100644 exercises/concept/enums/.meta/design.md create mode 100644 exercises/concept/numbers-floating-point/.meta/design.md create mode 100644 exercises/concept/numbers/.meta/design.md create mode 100644 exercises/concept/strings/.meta/design.md diff --git a/exercises/concept/bitwise-operations/.docs/after.md b/exercises/concept/bitwise-operations/.docs/after.md deleted file mode 100644 index 0ab09c70d6..0000000000 --- a/exercises/concept/bitwise-operations/.docs/after.md +++ /dev/null @@ -1,5 +0,0 @@ -# After - -- [Tutorial on working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. - -[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md new file mode 100644 index 0000000000..ea2ea5928e --- /dev/null +++ b/exercises/concept/dates/.meta/design.md @@ -0,0 +1,33 @@ +# Design + +## Goal + +TODO + +## Things to teach + +TODO + +## Things not to teach + +TODO + +## Resources to refer to + +TODO + +## Concepts + +TODO + +## Prequisites + +TODO + +## Representer + +TODO + +## Analyzer + +TODO diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/enums-advanced/.docs/after.md new file mode 100644 index 0000000000..a439989286 --- /dev/null +++ b/exercises/concept/enums-advanced/.docs/after.md @@ -0,0 +1,7 @@ +# After + +- [Working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. +- [Enum flags and bitwise operators][alanzucconi.com-enum-flags-and-bitwise-operators]. + +[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags +[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ diff --git a/exercises/concept/bitwise-operations/.docs/hints.md b/exercises/concept/enums-advanced/.docs/hints.md similarity index 100% rename from exercises/concept/bitwise-operations/.docs/hints.md rename to exercises/concept/enums-advanced/.docs/hints.md diff --git a/exercises/concept/bitwise-operations/.docs/instructions.md b/exercises/concept/enums-advanced/.docs/instructions.md similarity index 100% rename from exercises/concept/bitwise-operations/.docs/instructions.md rename to exercises/concept/enums-advanced/.docs/instructions.md diff --git a/exercises/concept/bitwise-operations/.docs/introduction.md b/exercises/concept/enums-advanced/.docs/introduction.md similarity index 100% rename from exercises/concept/bitwise-operations/.docs/introduction.md rename to exercises/concept/enums-advanced/.docs/introduction.md diff --git a/exercises/concept/bitwise-operations/.meta/Example.cs b/exercises/concept/enums-advanced/.meta/Example.cs similarity index 100% rename from exercises/concept/bitwise-operations/.meta/Example.cs rename to exercises/concept/enums-advanced/.meta/Example.cs diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/enums-advanced/.meta/design.md new file mode 100644 index 0000000000..21f54ed512 --- /dev/null +++ b/exercises/concept/enums-advanced/.meta/design.md @@ -0,0 +1,69 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student advanced aspects of the Concept of Enums in [C#][docs.microsoft.com-bitwise-and-shift-operators]. We'll do this in the form of working with [flag][docs.microsoft.com-flagsattribute] enums, which are enums whose values are interpreted as bitwise flags that can be manipulated through bitwise operations. + +## Things to teach + +After completing this exercise, the student should: + +- Know what a flags enumeration is. +- Know how to define a flags enumeration. +- Know how to check if a flag has been set on an enum value. +- Know how to set a flag on an enum value. +- Know how to unset a flag on an enum value. +- Know that an enum's underlying type can be changed. + +## Things not to teach + +As this is an advanced exercise, there are no enum-related things that we should explicitly _not_ teach. + +## Resources to refer to + +Here are some suggestions for resources to use in the exercise's documentation file(s): + +### Hints + +- [`switch` statement][docs.microsoft.com-switch-keyword] +- [Bitwise and shift operators][docs.microsoft.com-bitwise-and-shift-operators] + +### After + +- [Working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. +- [Enum flags and bitwise operators][alanzucconi.com-enum-flags-and-bitwise-operators] + +## Concepts + +The Concepts this exercise unlocks are: + +- `enums-advanced`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. + +## Prequisites + +This exercise's prerequisites Concepts are: + +- `enums-basic`: know how to define the `enum`. +- `attributes-basic`: know how to annotate the enum with the `[Flags]` attribute. +- `bitwise-operations`: know how to use bitwise operations to work with the flag enum values. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise could benefit from having an [analyzer][analyzer] that can comment on: + +- Verify that the `Permission` enum is marked with the `[Flags]` attribute. +- Suggest using `byte` as the enum's backing type if no backing type was explicitly specified. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags +[docs.microsoft.com-bitwise-and-shift-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators +[docs.microsoft.com-switch-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[docs.microsoft.com-binary-notation]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#integer-literals +[docs.microsoft.com-flagsattribute]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=netcore-3.1 +[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ +[concept-bitwise-manipulation]: ../../../../../reference/concepts/bitwise_manipulation.md diff --git a/exercises/concept/bitwise-operations/BitwiseOperations.cs b/exercises/concept/enums-advanced/EnumsAdvanced.cs similarity index 100% rename from exercises/concept/bitwise-operations/BitwiseOperations.cs rename to exercises/concept/enums-advanced/EnumsAdvanced.cs diff --git a/exercises/concept/bitwise-operations/BitwiseOperations.csproj b/exercises/concept/enums-advanced/EnumsAdvanced.csproj similarity index 100% rename from exercises/concept/bitwise-operations/BitwiseOperations.csproj rename to exercises/concept/enums-advanced/EnumsAdvanced.csproj diff --git a/exercises/concept/bitwise-operations/BitwiseOperationsTest.cs b/exercises/concept/enums-advanced/EnumsAdvancedTest.cs similarity index 100% rename from exercises/concept/bitwise-operations/BitwiseOperationsTest.cs rename to exercises/concept/enums-advanced/EnumsAdvancedTest.cs diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md new file mode 100644 index 0000000000..ea2ea5928e --- /dev/null +++ b/exercises/concept/enums/.meta/design.md @@ -0,0 +1,33 @@ +# Design + +## Goal + +TODO + +## Things to teach + +TODO + +## Things not to teach + +TODO + +## Resources to refer to + +TODO + +## Concepts + +TODO + +## Prequisites + +TODO + +## Representer + +TODO + +## Analyzer + +TODO diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md new file mode 100644 index 0000000000..ea2ea5928e --- /dev/null +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -0,0 +1,33 @@ +# Design + +## Goal + +TODO + +## Things to teach + +TODO + +## Things not to teach + +TODO + +## Resources to refer to + +TODO + +## Concepts + +TODO + +## Prequisites + +TODO + +## Representer + +TODO + +## Analyzer + +TODO diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md new file mode 100644 index 0000000000..ea2ea5928e --- /dev/null +++ b/exercises/concept/numbers/.meta/design.md @@ -0,0 +1,33 @@ +# Design + +## Goal + +TODO + +## Things to teach + +TODO + +## Things not to teach + +TODO + +## Resources to refer to + +TODO + +## Concepts + +TODO + +## Prequisites + +TODO + +## Representer + +TODO + +## Analyzer + +TODO diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md new file mode 100644 index 0000000000..ea2ea5928e --- /dev/null +++ b/exercises/concept/strings/.meta/design.md @@ -0,0 +1,33 @@ +# Design + +## Goal + +TODO + +## Things to teach + +TODO + +## Things not to teach + +TODO + +## Resources to refer to + +TODO + +## Concepts + +TODO + +## Prequisites + +TODO + +## Representer + +TODO + +## Analyzer + +TODO From 268b5849646cd55f27ede151e1fc16371cda4198 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 29 Jan 2020 18:05:20 +0000 Subject: [PATCH 016/327] Docs/design * [Docs] Add section on .meta/design.md document * [Docs] Add .meta/design.md file to file trees * [Docs] Use relative link * [Docs] Put meta design last * [Docs] Remove resources section --- exercises/concept/dates/.meta/design.md | 4 ---- exercises/concept/enums-advanced/.meta/design.md | 14 -------------- exercises/concept/enums/.meta/design.md | 4 ---- .../concept/numbers-floating-point/.meta/design.md | 4 ---- exercises/concept/numbers/.meta/design.md | 4 ---- exercises/concept/strings/.meta/design.md | 4 ---- 6 files changed, 34 deletions(-) diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index ea2ea5928e..f7dd5481dc 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -12,10 +12,6 @@ TODO TODO -## Resources to refer to - -TODO - ## Concepts TODO diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/enums-advanced/.meta/design.md index 21f54ed512..2ac9ac7b87 100644 --- a/exercises/concept/enums-advanced/.meta/design.md +++ b/exercises/concept/enums-advanced/.meta/design.md @@ -19,20 +19,6 @@ After completing this exercise, the student should: As this is an advanced exercise, there are no enum-related things that we should explicitly _not_ teach. -## Resources to refer to - -Here are some suggestions for resources to use in the exercise's documentation file(s): - -### Hints - -- [`switch` statement][docs.microsoft.com-switch-keyword] -- [Bitwise and shift operators][docs.microsoft.com-bitwise-and-shift-operators] - -### After - -- [Working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. -- [Enum flags and bitwise operators][alanzucconi.com-enum-flags-and-bitwise-operators] - ## Concepts The Concepts this exercise unlocks are: diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index ea2ea5928e..f7dd5481dc 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -12,10 +12,6 @@ TODO TODO -## Resources to refer to - -TODO - ## Concepts TODO diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md index ea2ea5928e..f7dd5481dc 100644 --- a/exercises/concept/numbers-floating-point/.meta/design.md +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -12,10 +12,6 @@ TODO TODO -## Resources to refer to - -TODO - ## Concepts TODO diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index ea2ea5928e..f7dd5481dc 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -12,10 +12,6 @@ TODO TODO -## Resources to refer to - -TODO - ## Concepts TODO diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index ea2ea5928e..f7dd5481dc 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -12,10 +12,6 @@ TODO TODO -## Resources to refer to - -TODO - ## Concepts TODO From 340a8800751e00dcb95352990d55bfac720f3178 Mon Sep 17 00:00:00 2001 From: Davy Jones Date: Thu, 30 Jan 2020 22:35:56 +0000 Subject: [PATCH 017/327] Fix small typo in C# Numbers Concept Exercise --- exercises/concept/numbers/NumbersTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/numbers/NumbersTest.cs b/exercises/concept/numbers/NumbersTest.cs index 38fc5138c4..2384932e65 100644 --- a/exercises/concept/numbers/NumbersTest.cs +++ b/exercises/concept/numbers/NumbersTest.cs @@ -35,10 +35,10 @@ public void WorkingItemsPerMinuteForSpeedFive() => Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); [Fact] - public void WorkingItemsPerMinuteForSpeedFour() => + public void WorkingItemsPerMinuteForSpeedEight() => Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); [Fact] public void WorkingItemsPerMinuteForSpeedTen() => Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); -} \ No newline at end of file +} From 5ee52402645e21fa2fa6f8b3a6834eacebe98e02 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 4 Feb 2020 10:26:06 +0100 Subject: [PATCH 018/327] Update Dates exercise to not require custom format string --- exercises/concept/dates/.meta/Example.cs | 2 +- exercises/concept/dates/DatesTest.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/exercises/concept/dates/.meta/Example.cs b/exercises/concept/dates/.meta/Example.cs index 761a8ef273..563057c525 100644 --- a/exercises/concept/dates/.meta/Example.cs +++ b/exercises/concept/dates/.meta/Example.cs @@ -12,5 +12,5 @@ public static bool IsAfternoonAppointment(DateTime appointmentDate) => appointmentDate.Hour >= 12 && appointmentDate.Hour < 18; public static string Description(DateTime appointmentDate) => - $"You have an appointment on {appointmentDate:dddd d MMMM yyyy} at {appointmentDate:HH:mm}."; + $"You have an appointment on {appointmentDate}."; } \ No newline at end of file diff --git a/exercises/concept/dates/DatesTest.cs b/exercises/concept/dates/DatesTest.cs index 0f943d2506..8ec50aea9f 100644 --- a/exercises/concept/dates/DatesTest.cs +++ b/exercises/concept/dates/DatesTest.cs @@ -94,15 +94,15 @@ public void IsAfternoonAppointmentForLateEveningAppointment() => [Fact] public void DescriptionOnFridayAfternoon() => - Assert.Equal("You have an appointment on Friday 29 March 2019 at 15:00.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); + Assert.Equal("You have an appointment on 3/29/2019 3:00:00 PM.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); [Fact] public void DescriptionOnThursdayAfternoon() => - Assert.Equal("You have an appointment on Thursday 25 July 2019 at 13:45.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); + Assert.Equal("You have an appointment on 7/25/2019 1:45:00 PM.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); [Fact] public void DescriptionOnWednesdayMorning() => - Assert.Equal("You have an appointment on Wednesday 9 September 2020 at 09:09.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); + Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] private class UseCultureAttribute : BeforeAfterTestAttribute From a20c991943347a0f5e394b70dc9a93118125f8b8 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 4 Feb 2020 10:26:42 +0100 Subject: [PATCH 019/327] Add design.md document for Dates exercise --- exercises/concept/dates/.meta/design.md | 34 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index f7dd5481dc..aee2206f97 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -2,28 +2,48 @@ ## Goal -TODO +The goal of this exercise is to teach the student the basics of the Concept of Dates through [C#][docs.microsoft.com-datetime]. ## Things to teach -TODO +After completing this exercise, the student should: + +- Know of the existence of the `DateTime` type. +- Know of the individual, date-related properties. +- Know how to access the current date. +- Know how to compare dates. +- Know how to convert a `string` to a `DateTime` and vice versa. ## Things not to teach -TODO +- Using standard or custom format strings. +- Everything related to timezones. +- Exact parsing using format strings. +- The `DateTimeOffset` type. +- The `TimeSpan` type. ## Concepts -TODO +The Concepts this exercise unlocks are: + +- `dates-basic`: know of the existence of the `DateTime` type; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa. +- `time-basic`: know of the existence of the `DateTime` type; know of the individual, time-related properties. ## Prequisites -TODO +This exercise's prerequisites Concepts are: + +- `numbers-basic`: know how to work with numbers. +- `strings-basic`: know how to work with strings. ## Representer -TODO +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -TODO +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-datetime]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 From a8173d25dbb075b47b12d3f765d8b809f2b91a44 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 4 Feb 2020 16:23:17 +0100 Subject: [PATCH 020/327] Add type conversion to introduction of numbers exercise --- exercises/concept/numbers/.docs/introduction.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index 18b2d775bd..ba1cf8b74c 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -6,3 +6,12 @@ There are two different types of numbers in C#: - Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. The two most common numeric types in C# are `int` and `double`. An `int` is a signed 32-bit integer and a `double` is a 64-bit floating-point number. + +## Converting between number types + +C# has two types of numeric conversions: + +1. Implicit conversions: no data will be lost and no additional syntax is required. +2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. + +As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. From fe675c61ae1ceda320c8aed5730d582e2ecb5bbb Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 5 Feb 2020 12:10:24 +0100 Subject: [PATCH 021/327] Add design document for numbers exercise --- exercises/concept/numbers/.meta/design.md | 28 +++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index f7dd5481dc..a24b3bd31e 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -2,28 +2,42 @@ ## Goal -TODO +The goal of this exercise is to teach the student how the Concept of Numbers is implemented in [C#][docs.microsoft.com-numbers]. It will introduce this concept through the two most common numeric types in C#: `int` (whole number) and `double` (floating-point number). ## Things to teach -TODO +After completing this exercise, the student should: + +- Know of the existence of the two most commonly used number types, `int` and `double`. +- Understand that an `int` represents whole numbers, and a `double` represents floating-point numbers. +- Know of basic operators such as multiplication and comparison. ## Things not to teach -TODO +- Any other numeric types besides `int` and `double` (so no `float`, `byte`, etc.). +- Parsing a `string` to an `int` or `double`. +- Converting an `int` or `double` to a `string`. ## Concepts -TODO +The Concepts this exercise unlocks are: + +- `numbers-basic`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; now of basic operators such as multiplication and comparison. +- `type-conversion-numbers`: know how to convert from one numeric type to another; know what implicit and explicit conversions are. +- `conditionals-if`: know how to conditionally execute code using an `if` statement. ## Prequisites -TODO +There are no prerequisites. ## Representer -TODO +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -TODO +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local From 3bf2404450b1b1252d9b16ac0491479eda0d74f4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 6 Feb 2020 09:48:29 +0100 Subject: [PATCH 022/327] Add design document for enums exercise * Add design document for enums exercise * Add stub method to enums exercise --- exercises/concept/enums/.meta/Example.cs | 10 +++---- exercises/concept/enums/.meta/design.md | 35 +++++++++++++++++++----- exercises/concept/enums/Enums.cs | 5 ++++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/enums/.meta/Example.cs index 2660a675d0..c05fcbabdd 100644 --- a/exercises/concept/enums/.meta/Example.cs +++ b/exercises/concept/enums/.meta/Example.cs @@ -11,11 +11,11 @@ public enum LogLevel public static class LogLine { public static LogLevel ParseLogLevel(string logLine) => - Enum.TryParse(GetLogLevel(logLine), ignoreCase: true, out var logLevel) ? logLevel : LogLevel.Unknown; - - private static string GetLogLevel(string logLine) => - logLine[1..(logLine.IndexOf(']'))]; + Enum.TryParse(GetLogLevel(logLine), true, out LogLevel logLevel) ? logLevel : LogLevel.Unknown; public static string OutputForShortLog(LogLevel logLevel, string message) => - $"{logLevel:D}:{message}"; + $"{(int)logLevel}:{message}"; + + private static string GetLogLevel(string logLine) => + logLine.Substring(1, logLine.IndexOf(']') - 1); } \ No newline at end of file diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index f7dd5481dc..479bd40442 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -2,28 +2,49 @@ ## Goal -TODO +The goal of this exercise is to teach the student the basics of the Concept of enums through [C#][docs.microsoft.com-enum]. ## Things to teach -TODO +After completing this exercise, the student should: + +- Know of the existence of the `enum` keyword. +- Know how to define enum members. +- Know how to assign values to enum members. +- Know how to get an enum's numeric value. +- Know how to convert a `string` to an `enum` and vice versa. ## Things not to teach -TODO +- Flag enums. +- That an enum's underlying type can be changed. +- Memory and performance characteristics. ## Concepts -TODO +The Concepts this exercise unlocks are: + +- `enums-basic`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert a `string` to an `enum` and vice versa. +- `conditionals-ternary`: know how to conditionally execute code using the ternary operator; know when to use the ternary operator. ## Prequisites -TODO +This exercise's prerequisites Concepts are: + +- `strings-basic`: log lines are `string` values. +- `numbers-basic`: enum values are assigned a numeric value. +- `generics`: generics are used to specify the enum type being parsed. +- `conditionals-if`: used to handle the case when the enum could not be parsed. +- `type-conversion-numbers`: casting the enum to an `int`. ## Representer -TODO +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -TODO +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-enum]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs index 43371916ec..3bb60cd33b 100644 --- a/exercises/concept/enums/Enums.cs +++ b/exercises/concept/enums/Enums.cs @@ -13,4 +13,9 @@ public static string OutputForShortLog(LogLevel logLevel, string message) { throw new NotImplementedException("Please implement the LogLine.OutputForShortLog method"); } + + private static string GetLogLevel(string logLine) + { + return logLine.Substring(1, logLine.IndexOf(']') - 1); + } } \ No newline at end of file From b991c2214cb8d602a013c31b9a31d351985d0ce8 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 6 Feb 2020 09:52:06 +0100 Subject: [PATCH 023/327] Add design document for numbers-floating-point exercise --- .../numbers-floating-point/.meta/design.md | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md index f7dd5481dc..18305c48af 100644 --- a/exercises/concept/numbers-floating-point/.meta/design.md +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -2,28 +2,45 @@ ## Goal -TODO +The goal of this exercise is to teach the student how the Concept of floating-point numbers is implemented in [C#][docs.microsoft.com-floating-point-numeric-types]. It will show the available floating-point types and discuss their differences. ## Things to teach -TODO +After completing this exercise, the student should: + +- Know of the existence of the three floating point types: `double`, `float` and `decimal`. +- Know when to use which type. +- Know how to write a `while` loop. ## Things not to teach -TODO +- Parsing floating-point types from strings. +- Converting floating-point types to strings. +- Using standard or custom format strings. ## Concepts -TODO +The Concepts this exercise unlocks are: + +- `numbers-floating-point`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which type. +- `loops-while`: know how to write a `while` loop. ## Prequisites -TODO +This exercise's prerequisites Concepts are: + +- `numbers-basic`: define numbers and apply arithmetic and boolean logic to them. +- `type-conversion-numbers`: convert from one floating-point type to another. +- `conditionals-if`: conditionally execute code based on value of floating-point numbers. ## Representer -TODO +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -TODO +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types From fcb3e2ea60407b830cba8602aa59642e9afca2ed Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 6 Feb 2020 09:55:40 +0100 Subject: [PATCH 024/327] Add design document for strings exercise * Replace "function" with "method" in docs * Add design document for strings exercise --- exercises/concept/strings/.meta/design.md | 25 ++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index f7dd5481dc..ad31dfc01b 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -2,28 +2,39 @@ ## Goal -TODO +The goal of this exercise is to teach the student the basics of the Concept of Strings in [C#][docs.microsoft.com-string]. ## Things to teach -TODO +- Know of the existence of the `string` type. +- Know how to create a string. +- Know of some basic string methods (like finding the index of a character at a position, or returning a part the string). +- Know how to do basic string formatting. ## Things not to teach -TODO +- Using standard or custom format strings. +- Memory and performance characteristics. +- Strings can be enumerated. ## Concepts -TODO +The Concepts this exercise unlocks are: + +- `strings-basic`: know of the existence of the `string` type; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string formatting. ## Prequisites -TODO +There are no prerequisites. ## Representer -TODO +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -TODO +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 From 225b0b99d87c584949308124ac4ccb38e4f7f0bb Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 6 Feb 2020 09:56:48 +0100 Subject: [PATCH 025/327] Be explicit about why prerequisites are needed in design document * Be explicit about why prerequisites are needed in design document of dates Co-authored-by: Rob Keim --- exercises/concept/dates/.meta/design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index aee2206f97..92db0ca965 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -33,8 +33,8 @@ The Concepts this exercise unlocks are: This exercise's prerequisites Concepts are: -- `numbers-basic`: know how to work with numbers. -- `strings-basic`: know how to work with strings. +- `numbers-basic`: comparing the hour against specific number values. +- `strings-basic`: dates are parsed from and converted to strings. ## Representer From 24c1fec0b7c9763749be892b190acc2e3f868f45 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 7 Feb 2020 16:47:00 +0100 Subject: [PATCH 026/327] Extract concepts from v2 grade-school exercise Extract concepts from v2 grade-school exercise Co-authored-by: Rob Keim --- reference/exercise-concepts/grade-school.md | 24 +++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 reference/exercise-concepts/grade-school.md diff --git a/reference/exercise-concepts/grade-school.md b/reference/exercise-concepts/grade-school.md new file mode 100644 index 0000000000..251858424e --- /dev/null +++ b/reference/exercise-concepts/grade-school.md @@ -0,0 +1,24 @@ +# Concepts of grade-school + +[Example implementation](https://exercism.io/tracks/csharp/exercises/grade-school/solutions/2fd52e1bbfcecdfaff4075c4) + +## General + +- functions: used as the main entry point for the exercise +- function arguments: student name and grade is passed as an input argument +- return values: returning a value from a method +- scoping: use `{` and `}` to denote scoping +- interfaces: the type returned is an `IEnumerable` +- classes: the tested method is defined in a class +- objects: creating an instance of the `SortedList` class +- state: keeping track of the grades +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `SortedList` class +- assignment: assigning values, such as the dictionary +- mutation: mutating the sorted list after it has been created +- mapping, selecting, ordering enumerables: using multiple LINQ methods to manipulate enumerables (`Where`, `OrderBy`, `Select`, `ToArray`) +- strings: a `string` is used for a student +- integers: an `int` is used for a grade +- dictionaries: a `SortedList` is used as to store the student to grade mapping +- equality operator: `==` From c9a624bb53f9edae1659265689ffb38dbf722235 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sun, 9 Feb 2020 15:54:02 +0100 Subject: [PATCH 027/327] Extract concepts from v2 change exercise Extract concepts from v2 change exercise Co-Authored-By: Rob Keim --- reference/exercise-concepts/change.md | 36 +++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 reference/exercise-concepts/change.md diff --git a/reference/exercise-concepts/change.md b/reference/exercise-concepts/change.md new file mode 100644 index 0000000000..75414a33da --- /dev/null +++ b/reference/exercise-concepts/change.md @@ -0,0 +1,36 @@ +# Concepts of change + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/change/Example.cs) + +## General + +- functions: used as the main entry point for the exercise +- function arguments: input coins and target are passed as arguments +- out parameters: used when retrieving a value from the dictionary +- return values: returning a value from a method +- conditionals using if: conditionally execute logic using an `if` statement and the ternary operator +- exceptions: throw an exception in the event of invalid input +- scoping: use `{` and `}` to denote scoping +- classes: the tested method is defined in a class +- objects: creating an object to keep track of the coins +- members: methods linked to a class instance +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `List` and `Dictionary` classes +- type inference: using `var` to define the complex types (dictionaries) +- assignment: assigning values, such as the minimalCoinsMap +- mutation: mutating the dictionary after it has been created +- mapping, selecting, ordering enumerables: using multiple LINQ methods to manipulate enumerables (`Min`, `Where`, `OrderBy`, `Select`, `Aggregate`, `FirstOrDefault`, `ToList`, `ToArray`) +- ranges: a range is created for iterating over all values up to the target +- object initializers: initializing dictionary through object initializer +- integers: an `int` is used for a coin and the target +- array: a `int []` is used for the available coinage +- lists: a `List` is used as to store the coins for a given value in +- nulls: a `null` value is used as a default +- ordering operators:`<`, `>`, `<=` +- equality operator: `!=` +- math operators: `-`, is used + +## Approach: nested functions + +- nested functions: using a nested method to simplify argument passing From 59f1006f40c60f639fd4a3cda1553ebc53c09573 Mon Sep 17 00:00:00 2001 From: Petru Faurescu Date: Tue, 11 Feb 2020 09:46:21 +0100 Subject: [PATCH 028/327] Extract concepts from v2 exercise two-fer Extract concepts from v2 exercise two-fer --- reference/exercise-concepts/two-fer.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 reference/exercise-concepts/two-fer.md diff --git a/reference/exercise-concepts/two-fer.md b/reference/exercise-concepts/two-fer.md new file mode 100644 index 0000000000..bd25601a2f --- /dev/null +++ b/reference/exercise-concepts/two-fer.md @@ -0,0 +1,16 @@ +# Concepts of Two Fer + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/two-fer/Example.cs) + +## General +- function: used as the entry point to this exercise +- static function: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- strings: used to format and return the result +- function arguments: need to add one optional argument - it would be avoided an unnecessary method overloading, keep the code simpler +- class: the tested method is defined in a class +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements + +## Optional, optimizing the code +- string interpolation: while `string` could be formatted in different ways, string interpolation provides a more effective and simpler way +- expression body method: it makes the code cleaner for a short (one-line) method From a60f8b59e89be06193e81e4d70b5467c90b99edf Mon Sep 17 00:00:00 2001 From: Brandon Everett Date: Tue, 11 Feb 2020 09:59:23 -0500 Subject: [PATCH 029/327] extract concepts of v2 isbn-verifier exercise * extract concepts of v2 isbn-verifier exercise * Update isbn-verifier.md * update isbn-verifier with suggestions --- reference/exercise-concepts/isbn-verifier.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 reference/exercise-concepts/isbn-verifier.md diff --git a/reference/exercise-concepts/isbn-verifier.md b/reference/exercise-concepts/isbn-verifier.md new file mode 100644 index 0000000000..7778850be7 --- /dev/null +++ b/reference/exercise-concepts/isbn-verifier.md @@ -0,0 +1,18 @@ +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/isbn-verifier/Example.cs) + + ## General + - functions: used as the main entry point to this exercise + - static functions: used as the main entry point to this exercise + - function arguments: input string is passed as an argument + - return values: returning value from method + - visibility: test class and test methods are `public` + - imports: importing types with using statements + - namespaces: knowing where to find Regular Expression methods + - regex: use regex to implement the checker + - strings: used to store the isbn numbers + - for loop: iterate over the numbers to check if valid + - conditionals: used for checking values + - ternary operator: combine conditonals to check for isbn + - assignment: assigning values to variables + - type inference: using var to define variables + - math operators: `++` and `--` used to increment counts in loop, modulus operator From 9abc6e5aa3e7fc304eed173f484947364ffbe748 Mon Sep 17 00:00:00 2001 From: Marcos Almeida Date: Wed, 12 Feb 2020 07:55:15 +0100 Subject: [PATCH 030/327] Extract Concepts from v2 exercise: rna-transcriptions * very first draft * second pass * For consistency Co-Authored-By: Rob Keim * add example implementations Co-authored-by: Rob Keim --- .../exercise-concepts/rna-trascriptions.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 reference/exercise-concepts/rna-trascriptions.md diff --git a/reference/exercise-concepts/rna-trascriptions.md b/reference/exercise-concepts/rna-trascriptions.md new file mode 100644 index 0000000000..77d6fd8f5a --- /dev/null +++ b/reference/exercise-concepts/rna-trascriptions.md @@ -0,0 +1,44 @@ +# RNA transcription + +## Example implementations + +- [Using Linq and Dictionary](https://exercism.io/tracks/csharp/exercises/rna-transcription/solutions/9cd192112635494cbc16743f3877a9c6) +- [Using a StringBuilder, foreach and a Dictionary](https://exercism.io/tracks/csharp/exercises/rna-transcription/solutions/82fac18e0003494b8639bb80ac2ed0ce) +- [Using Linq and a switch](https://exercism.io/tracks/csharp/exercises/rna-transcription/solutions/15f7659e6f794051b337cbefa0c10259) + +## Object-oriented + +- Classes: used on the template. Some people define a static dictionary to pre compute RNA pairs. +- Encapsulation: used on the template. There are public elements, some people create private elements. +- Methods: used on the template. One needs to implement a method. + +## Functional + +- Pipelines (LINQ): some solutions use that to process the string chars. +- Immutability: some people create readonly pre computed dictionaries. +- Anonymous methods: necessary when using Linq. +- Pattern matching: some solutions use switches. +- Higher-order functions: Linq is basically that? +- Local functions: is it a lambda? + +## General + +- Generics: when people use Dictionaries they need that. +- Conditionals: used to compute pairs. +- Enumeration: to process all chars on the string. +- Namespaces: used on the template. +- Exception handling: some people use that to detect errors. Even though it is not required by the tests. +- Nullability: some people need to check for nulls. + +## Types + +- Strings: the basis of the exercice. I think things like Concat/Join/+/StringBuilder/ToString are problably concepts by themselves. +- Lists: used as intermediate data structure. +- Dictionaries: used to store pre computed RNA pairs. +- Arrays: used as intermediate data structure. +- Characters: we can either use only strings or only chars to solve the exercise. + +## Missing + +- Comments +- Naming conventions From 9b286f4a66582d7f637c11b9a646fb69ca359990 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 12 Feb 2020 18:21:44 +0100 Subject: [PATCH 031/327] Update design of numbers exercise --- exercises/concept/numbers/.meta/design.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index a24b3bd31e..da218611ce 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -11,6 +11,8 @@ After completing this exercise, the student should: - Know of the existence of the two most commonly used number types, `int` and `double`. - Understand that an `int` represents whole numbers, and a `double` represents floating-point numbers. - Know of basic operators such as multiplication and comparison. +- Know how to convert from one numeric type to another; know what implicit and explicit conversions are. +- Know how to conditionally execute code using an `if` statement. ## Things not to teach From ac9862f4150dd9a75224571d93747c8748a6577d Mon Sep 17 00:00:00 2001 From: Petru Faurescu Date: Thu, 13 Feb 2020 08:19:24 +0100 Subject: [PATCH 032/327] Extract concepts from v2 exercise: leap Extract concepts from v2 exercise: leap --- reference/exercise-concepts/leap.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 reference/exercise-concepts/leap.md diff --git a/reference/exercise-concepts/leap.md b/reference/exercise-concepts/leap.md new file mode 100644 index 0000000000..686bcadbc5 --- /dev/null +++ b/reference/exercise-concepts/leap.md @@ -0,0 +1,23 @@ +# Concepts of Leap + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/leap/Example.cs) + +## General +- functions: used as the entry point to this exercise +- static functions: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- classes: the tested method is defined in a class +- static class: a static class cannot be instantiated. Because there is no instance variable, members of a static class could be access by using the class name itself +- function argument: use input argument passed to parameter by value +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- integers +- booleans: using comparison operator `==` as well as conditional operators +- artithmetic operator: use remainder operator `%`, checking if year is divisible with reference years (4, 100, 400) +- boolean operators: use conditional logical AND operator `&&` as well as conditional logical OR operator `||`. These greatly simplifies the code, avoiding if statements +- operator precedence: conditional AND operator has a higher precedence than conditional logical OR +- parentheses and operator precedence: Use parentheses `()` to change the order of evaluation imposed by operator precedence + +## Optional, optimizing the code +- boolean expression: function could be written as a single combined boolean expression +- order of the validation: years divisible with 4 are more common, and adding this condition as first, removes the necessity to execute the other checks. Similar to 100 comparing to 400. +- expression body method: it makes the code cleaner for a short (one-line) method From f9c1d09e501fd66f0528e5cddd317b068c8fd326 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 14 Feb 2020 11:20:48 +0000 Subject: [PATCH 033/327] created document out-of-scope created document out-of-scope --- reference/out-of-scope.md | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 reference/out-of-scope.md diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md new file mode 100644 index 0000000000..2f4132a0bc --- /dev/null +++ b/reference/out-of-scope.md @@ -0,0 +1,36 @@ +# Topics Falling Outside of the Scope of Exercism's C# Track + +This document provides examples of material that falls outside of +Exercism's scope. It indicates the limits of what can be +directly taught by the exercises. + +The document should answer the question +"Is topic or skill x covered by Exercism?". + +The material should be capable of being communicated to an enquiring +student as and when required. + +Where material is covered under "What not to teach" in _design.md_ +for a particular exercise it should not be repeated here +unless it is felt that the topic otherwise has insufficient prominence. + +### 3rd Party and Microsoft Libraries +- JSON.net +- NodaTime +- .NET Forms +- WPF + +### Frameworks +- .NET Framework +- ASP.NET (Core) +- Unity + +### Platform +- .NET interop (e.g. with Visual Basic or F#) +- NuGet +- Project/solution files + +### Other +- File handling +- Networking +- Compiler directives \ No newline at end of file From 2c5a0e113504d4fc4538b0f105c6c79954ef8797 Mon Sep 17 00:00:00 2001 From: archrisV Date: Fri, 14 Feb 2020 16:06:24 +0100 Subject: [PATCH 034/327] Extract space-age Concepts Extract space-age Concepts Co-authored-by: Erik Schierboom --- reference/exercise-concepts/space-age.md | 26 ++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 reference/exercise-concepts/space-age.md diff --git a/reference/exercise-concepts/space-age.md b/reference/exercise-concepts/space-age.md new file mode 100644 index 0000000000..2970431793 --- /dev/null +++ b/reference/exercise-concepts/space-age.md @@ -0,0 +1,26 @@ +# Concepts of Space age + +[Example implementation](https://github.com/exercism/csharp/blob/master/exercises/space-age/Example.cs) + +## General +- methods: used as the entry points to this exercise +- class: the tested methods are defined in a class +- class constructor: SpaceAge class uses a constructor to assign the amount of seconds +- visibility: making tested method and tested class `public` while making class members which contain data `private` +- imports: import types through `using` statements +- expression-bodied members: it makes the code cleaner for On{Planet} methods +- double: the return value of the On{Planet} methods and the argument of the class constructor is of type double, meaning the user must be exposed to working with floating point numbers +- division operator: user must know how to use binary arithmetic operators + +## Approach using constants +- const: each orbital period for a planet can be stored into a constant field to prevent modification of the values + +## Approach using Dictionary class +- using: import proper namespace for access to the Dictionary Class (System.Collections.Generic) +- dictionaries : use the Dictionary class to store factors on each planet +- object initializers: create a dictionary with proper type for keys and values, assign proper combinations of key-value pairs +- indexers: used to retrieve values by their specified keys + +## Approach using Enums +- enum: can be used as a Key for the Dictionary class instead of a string + From 6587cb6b4a7e11a0780e528b478dfa6814e8ff78 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 14 Feb 2020 16:08:17 +0100 Subject: [PATCH 035/327] Add contributors --- exercises/concept/dates/.meta/config.json | 8 ++++++++ exercises/concept/enums-advanced/.meta/config.json | 8 ++++++++ exercises/concept/enums/.meta/config.json | 8 ++++++++ exercises/concept/numbers/.meta/config.json | 8 ++++++++ exercises/concept/strings/.meta/config.json | 8 ++++++++ 5 files changed, 40 insertions(+) create mode 100644 exercises/concept/dates/.meta/config.json create mode 100644 exercises/concept/enums-advanced/.meta/config.json create mode 100644 exercises/concept/enums/.meta/config.json create mode 100644 exercises/concept/numbers/.meta/config.json create mode 100644 exercises/concept/strings/.meta/config.json diff --git a/exercises/concept/dates/.meta/config.json b/exercises/concept/dates/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/dates/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/enums-advanced/.meta/config.json b/exercises/concept/enums-advanced/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/enums-advanced/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/enums/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/enums/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/numbers/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/strings/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} From b85097f8d906f31e8843d6c5a319a0f5178d74db Mon Sep 17 00:00:00 2001 From: Richard Leurs <7275740+EarthlingRich@users.noreply.github.com> Date: Sat, 15 Feb 2020 12:46:44 +0100 Subject: [PATCH 036/327] Feedback on numbers exercise * Implement feedback on numbers exercise. * Fix example SuccessRate method. --- exercises/concept/numbers/.docs/hints.md | 2 +- exercises/concept/numbers/.docs/instructions.md | 3 +-- exercises/concept/numbers/.docs/introduction.md | 2 +- exercises/concept/numbers/.meta/Example.cs | 9 +++------ 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md index 74197ec4fc..94df0c6a0c 100644 --- a/exercises/concept/numbers/.docs/hints.md +++ b/exercises/concept/numbers/.docs/hints.md @@ -14,7 +14,7 @@ ### 2. Calculate the number of working items produced per second -- Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][docs-microsoft.com-convert] or [cast to an int][tutorial-dotnetperls.com-cast-int]. +- Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that an `int` has less precision than a `double` so rounding has to be applied, also the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][docs-microsoft.com-convert] or [cast to an int][tutorial-dotnetperls.com-cast-int]. [docs-microsoft.com-convert]: https://docs.microsoft.com/en-us/dotnet/api/system.convert?view=netcore-3.0#examples [tutorial-dotnetperls.com-cast-int]: https://www.dotnetperls.com/cast-int diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index bf2c6856a1..b91a4d9b81 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -2,9 +2,8 @@ In this exercise you'll be writing code to analyze the production of an assembly line in a car factory. The assembly line's speed can range from `0` (off) to `10` (maximum). -At its default speed (`1`), `221` cars are produced each hour. In principle, the production increases linearly. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate: +At its lowest speed (`1`), `221` cars are produced each hour. The production increases linearly with the speed. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate: -- `0`: 0% success rate. - `1` to `4`: 100% success rate. - `5` to `8`: 90% success rate. - `9` and `10`: 77% success rate. diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index ba1cf8b74c..d6b98469bf 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -5,7 +5,7 @@ There are two different types of numbers in C#: - Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. - Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. -The two most common numeric types in C# are `int` and `double`. An `int` is a signed 32-bit integer and a `double` is a 64-bit floating-point number. +The two most common numeric types in C# are `int` and `double`. An `int` is a 32-bit integer and a `double` is a 64-bit floating-point number. ## Converting between number types diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index 49a755b467..61974b04d6 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -13,15 +13,12 @@ public static int WorkingItemsPerMinute(int speed) => private static double SuccessRate(int speed) { - if (speed == 0) - return 0.0; - if (speed >= 9) return 0.77; - if (speed < 5) - return 1.0; + if (speed >= 5) + return 0.9; - return 0.9; + return 1; } } \ No newline at end of file From 70c3636f85ddeff401c911929ed794ef7e63cf9b Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 18 Feb 2020 08:33:04 +0100 Subject: [PATCH 037/327] Normalize format of exercise-concepts * Normalize format of exercise-concepts --- reference/exercise-concepts/book-store.md | 8 ++-- reference/exercise-concepts/isbn-verifier.md | 33 ++++++------- reference/exercise-concepts/leap.md | 18 ++++---- .../exercise-concepts/protein-translation.md | 8 ++-- .../exercise-concepts/rna-trascriptions.md | 46 +++++++++---------- reference/exercise-concepts/robot-name.md | 2 +- reference/exercise-concepts/two-fer.md | 11 ++--- 7 files changed, 63 insertions(+), 63 deletions(-) diff --git a/reference/exercise-concepts/book-store.md b/reference/exercise-concepts/book-store.md index 84c681e11d..7ce0ea60d8 100644 --- a/reference/exercise-concepts/book-store.md +++ b/reference/exercise-concepts/book-store.md @@ -26,8 +26,10 @@ - math standard library: use of `Math.Round` and `Math.Min` - mapping, selecting, ordering enumerables: using multiple Linq methods to manipulate enumerables (`Concat`, `GroupBy`, `Min`, `OrderByDescending`, `Select`, `Take`, `ToArray`, `Where`) -## Switch for discount percentage +## Approach: switch + - switch: used to map the discount percentage based on the number of unique books -## Dictionary for discount percentages -- dictionaries: `Dictionary` for mapping the discount percentage based on the number of unique books \ No newline at end of file +## Approach: dictionary + +- dictionaries: `Dictionary` for mapping the discount percentage based on the number of unique books diff --git a/reference/exercise-concepts/isbn-verifier.md b/reference/exercise-concepts/isbn-verifier.md index 7778850be7..e225fda70e 100644 --- a/reference/exercise-concepts/isbn-verifier.md +++ b/reference/exercise-concepts/isbn-verifier.md @@ -1,18 +1,19 @@ [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/isbn-verifier/Example.cs) - ## General - - functions: used as the main entry point to this exercise - - static functions: used as the main entry point to this exercise - - function arguments: input string is passed as an argument - - return values: returning value from method - - visibility: test class and test methods are `public` - - imports: importing types with using statements - - namespaces: knowing where to find Regular Expression methods - - regex: use regex to implement the checker - - strings: used to store the isbn numbers - - for loop: iterate over the numbers to check if valid - - conditionals: used for checking values - - ternary operator: combine conditonals to check for isbn - - assignment: assigning values to variables - - type inference: using var to define variables - - math operators: `++` and `--` used to increment counts in loop, modulus operator +## General + +- functions: used as the main entry point to this exercise +- static functions: used as the main entry point to this exercise +- function arguments: input string is passed as an argument +- return values: returning value from method +- visibility: test class and test methods are `public` +- imports: importing types with using statements +- namespaces: knowing where to find Regular Expression methods +- regex: use regex to implement the checker +- strings: used to store the isbn numbers +- for loop: iterate over the numbers to check if valid +- conditionals: used for checking values +- ternary operator: combine conditonals to check for isbn +- assignment: assigning values to variables +- type inference: using var to define variables +- math operators: `++` and `--` used to increment counts in loop, modulus operator diff --git a/reference/exercise-concepts/leap.md b/reference/exercise-concepts/leap.md index 686bcadbc5..05f29d0fec 100644 --- a/reference/exercise-concepts/leap.md +++ b/reference/exercise-concepts/leap.md @@ -3,21 +3,23 @@ [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/leap/Example.cs) ## General + - functions: used as the entry point to this exercise -- static functions: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- static functions: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. - classes: the tested method is defined in a class -- static class: a static class cannot be instantiated. Because there is no instance variable, members of a static class could be access by using the class name itself +- static class: a static class cannot be instantiated. Because there is no instance variable, members of a static class could be access by using the class name itself - function argument: use input argument passed to parameter by value - visibility: making tested method and tested class `public` - imports: import types through `using` statements - integers -- booleans: using comparison operator `==` as well as conditional operators -- artithmetic operator: use remainder operator `%`, checking if year is divisible with reference years (4, 100, 400) +- booleans: using comparison operator `==` as well as conditional operators +- artithmetic operator: use remainder operator `%`, checking if year is divisible with reference years (4, 100, 400) - boolean operators: use conditional logical AND operator `&&` as well as conditional logical OR operator `||`. These greatly simplifies the code, avoiding if statements -- operator precedence: conditional AND operator has a higher precedence than conditional logical OR +- operator precedence: conditional AND operator has a higher precedence than conditional logical OR - parentheses and operator precedence: Use parentheses `()` to change the order of evaluation imposed by operator precedence -## Optional, optimizing the code +## Approach: single boolean expression + - boolean expression: function could be written as a single combined boolean expression -- order of the validation: years divisible with 4 are more common, and adding this condition as first, removes the necessity to execute the other checks. Similar to 100 comparing to 400. -- expression body method: it makes the code cleaner for a short (one-line) method +- order of the validation: years divisible with 4 are more common, and adding this condition as first, removes the necessity to execute the other checks. Similar to 100 comparing to 400. +- expression body method: it makes the code cleaner for a short (one-line) method diff --git a/reference/exercise-concepts/protein-translation.md b/reference/exercise-concepts/protein-translation.md index fcaa0516cc..2fe70e200e 100644 --- a/reference/exercise-concepts/protein-translation.md +++ b/reference/exercise-concepts/protein-translation.md @@ -15,16 +15,16 @@ - new keyword: used to instantiate a class - lists: a `List` temporarily holds the results before converting them to an array (Add and ToArray methods) - for loop: iterate through the strands -- integers: `int` type used as a counter in the loop +- integers: `int` type used as a counter in the loop - math operations: <, *, and ++ - strings: substring and comparison - exceptions: throw an exception in the event of invalid input -## Using a switch for mapping the proteins +## Approach: switch - switch cases: to convert the string to a protein name (including default case) -## Using a dictionary for mapping the proteins +## Approach: dictionary - dictionaries: `Dictionary` is used to store a mapping -- immutable data structures: `ReadonlyDictionary` should be used for the mapping which never changes \ No newline at end of file +- immutable data structures: `ReadonlyDictionary` should be used for the mapping which never changes diff --git a/reference/exercise-concepts/rna-trascriptions.md b/reference/exercise-concepts/rna-trascriptions.md index 77d6fd8f5a..5957f33fab 100644 --- a/reference/exercise-concepts/rna-trascriptions.md +++ b/reference/exercise-concepts/rna-trascriptions.md @@ -8,37 +8,33 @@ ## Object-oriented -- Classes: used on the template. Some people define a static dictionary to pre compute RNA pairs. -- Encapsulation: used on the template. There are public elements, some people create private elements. -- Methods: used on the template. One needs to implement a method. +- classes: used on the template. Some people define a static dictionary to pre compute RNA pairs. +- encapsulation: used on the template. There are public elements, some people create private elements. +- methods: used on the template. One needs to implement a method. ## Functional -- Pipelines (LINQ): some solutions use that to process the string chars. -- Immutability: some people create readonly pre computed dictionaries. -- Anonymous methods: necessary when using Linq. -- Pattern matching: some solutions use switches. -- Higher-order functions: Linq is basically that? -- Local functions: is it a lambda? +- pipelines (LINQ): some solutions use that to process the string chars. +- immutability: some people create readonly pre computed dictionaries. +- anonymous methods: necessary when using Linq. +- pattern matching: some solutions use switches. +- higher-order functions: Linq is basically that? +- local functions: is it a lambda? ## General -- Generics: when people use Dictionaries they need that. -- Conditionals: used to compute pairs. -- Enumeration: to process all chars on the string. -- Namespaces: used on the template. -- Exception handling: some people use that to detect errors. Even though it is not required by the tests. -- Nullability: some people need to check for nulls. +- generics: when people use Dictionaries they need that. +- conditionals: used to compute pairs. +- enumeration: to process all chars on the string. +- namespaces: used on the template. +- exception handling: some people use that to detect errors. Even though it is not required by the tests. +- nullability: some people need to check for nulls. +- comments ## Types -- Strings: the basis of the exercice. I think things like Concat/Join/+/StringBuilder/ToString are problably concepts by themselves. -- Lists: used as intermediate data structure. -- Dictionaries: used to store pre computed RNA pairs. -- Arrays: used as intermediate data structure. -- Characters: we can either use only strings or only chars to solve the exercise. - -## Missing - -- Comments -- Naming conventions +- strings: the basis of the exercice. I think things like Concat/Join/+/StringBuilder/ToString are problably concepts by themselves. +- lists: used as intermediate data structure. +- dictionaries: used to store pre computed RNA pairs. +- arrays: used as intermediate data structure. +- characters: we can either use only strings or only chars to solve the exercise. diff --git a/reference/exercise-concepts/robot-name.md b/reference/exercise-concepts/robot-name.md index a1a2d1ccfa..1782492b68 100644 --- a/reference/exercise-concepts/robot-name.md +++ b/reference/exercise-concepts/robot-name.md @@ -3,6 +3,7 @@ [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/robot-name/Example.cs) ## General + - functions: used as the main entry point to this exercise - constructors: initalizing values when object is created - conditionals using if: conditionally execute logic using an `if` statement @@ -18,4 +19,3 @@ - namespaces: knowing where to find the `HashSet` class - do while loop: loop to find valid names - regex: test suite uses regex to test valid names - diff --git a/reference/exercise-concepts/two-fer.md b/reference/exercise-concepts/two-fer.md index bd25601a2f..989bccbad5 100644 --- a/reference/exercise-concepts/two-fer.md +++ b/reference/exercise-concepts/two-fer.md @@ -3,14 +3,13 @@ [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/two-fer/Example.cs) ## General + - function: used as the entry point to this exercise -- static function: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- static function: the `static` keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. - strings: used to format and return the result -- function arguments: need to add one optional argument - it would be avoided an unnecessary method overloading, keep the code simpler +- function arguments: need to add one optional argument - it would be avoided an unnecessary method overloading, keep the code simpler - class: the tested method is defined in a class - visibility: making tested method and tested class `public` - imports: import types through `using` statements - -## Optional, optimizing the code -- string interpolation: while `string` could be formatted in different ways, string interpolation provides a more effective and simpler way -- expression body method: it makes the code cleaner for a short (one-line) method +- string interpolation: while `string` could be formatted in different ways, string interpolation provides a more effective and simpler way +- expression body method: it makes the code cleaner for a short (one-line) method From ca2612afa9f60fbb58579825f04e00ba6176748d Mon Sep 17 00:00:00 2001 From: Ranga Senal Fernando Date: Wed, 19 Feb 2020 22:32:02 +1100 Subject: [PATCH 038/327] Create resistor-color.md Extract all most all the concepts used to solve the resistor-color exercise --- reference/exercise-concepts/resistor-color.md | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 reference/exercise-concepts/resistor-color.md diff --git a/reference/exercise-concepts/resistor-color.md b/reference/exercise-concepts/resistor-color.md new file mode 100644 index 0000000000..1f6b386217 --- /dev/null +++ b/reference/exercise-concepts/resistor-color.md @@ -0,0 +1,23 @@ +# Concepts of Resistor Color + +[Example implementation](https://exercism.io/tracks/csharp/exercises/resistor-color/solutions) + +## General + +- functions: used as the main entry point for the exercise +- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- function arguments: input color is passed as an arguments +- return values: returning a value from a method +- exceptions: throw an exception in the event of invalid/null input +- scoping: use `{` and `}` to denote scoping +- classes: the tested method is defined in a class +- objects: creating an object to keep track of the rolls +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `Array` class +- expression body method: it makes the code cleaner for a short (one-line) method +- immutability: defining the colors in an array as `readonly` +- string: array elements defined as string +- array: creating an array to hold list of colors +- static method: to access metods at the type level. +- int: return sign integers From 26694ee95c8206270bda3e545e2e7deee0b1dd57 Mon Sep 17 00:00:00 2001 From: Ranga Senal Fernando Date: Wed, 19 Feb 2020 23:15:46 +1100 Subject: [PATCH 039/327] rectify a wrong definition make sure to add the correct definition to the correct concept. --- reference/exercise-concepts/resistor-color.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/exercise-concepts/resistor-color.md b/reference/exercise-concepts/resistor-color.md index 1f6b386217..61a670de55 100644 --- a/reference/exercise-concepts/resistor-color.md +++ b/reference/exercise-concepts/resistor-color.md @@ -11,7 +11,7 @@ - exceptions: throw an exception in the event of invalid/null input - scoping: use `{` and `}` to denote scoping - classes: the tested method is defined in a class -- objects: creating an object to keep track of the rolls +- objects: creating an object to keep list of colors - visibility: making tested method and tested class `public` - imports: import types through `using` statements - namespaces: knowing where to find the `Array` class From 350c362d2f0ca79f48bbe44a41995edf6068fd9c Mon Sep 17 00:00:00 2001 From: Ranga Senal Fernando Date: Wed, 19 Feb 2020 23:43:21 +1100 Subject: [PATCH 040/327] Create gigasecond.md Extract concepts that has been used for this exercise --- reference/exercise-concepts/gigasecond.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 reference/exercise-concepts/gigasecond.md diff --git a/reference/exercise-concepts/gigasecond.md b/reference/exercise-concepts/gigasecond.md new file mode 100644 index 0000000000..bbfe4cefd6 --- /dev/null +++ b/reference/exercise-concepts/gigasecond.md @@ -0,0 +1,20 @@ +# Concepts of Gigasecond + +[Example implementation](https://exercism.io/tracks/csharp/exercises/gigasecond/solutions) + +## General + +- functions: used as the main entry point for the exercise +- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- function arguments: input 'moment' is passed as an arguments +- return values: returning a value from a method +- scoping: use `{` and `}` to denote scoping +- type inference: using `var` to define the seconds +- classes: the tested method is defined in a class +- visibility: making tested method and tested class `public` +- imports: import types through `using` statements +- namespaces: knowing where to find the `DateTime` class +- expression body method: it makes the code cleaner for a short (one-line) method +- Exponential (scientific): use to represent numbers e.g 1e9 to represent 1000000000 +- static method: to access metods at the type level. +- DateTime: Represents a date and time of a day. From ea236158fcb7a0b7214d7c0dbb960516534d6064 Mon Sep 17 00:00:00 2001 From: Petru Faurescu Date: Thu, 20 Feb 2020 09:02:40 +0100 Subject: [PATCH 041/327] Extract concepts from v2 exercise: high-scores (new) --- reference/exercise-concepts/high-scores.md | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 reference/exercise-concepts/high-scores.md diff --git a/reference/exercise-concepts/high-scores.md b/reference/exercise-concepts/high-scores.md new file mode 100644 index 0000000000..07eeffd345 --- /dev/null +++ b/reference/exercise-concepts/high-scores.md @@ -0,0 +1,44 @@ +# Concepts of high-scores + +## Example implementations +- [Using Generic Collections and LINQ](https://exercism.io/tracks/csharp/exercises/high-scores/solutions/aa676c4a13344a5a9c7b7b944b5f3ad6) +- [Using Generic Collections, Sorted list, and Enumeration loops](https://exercism.io/tracks/csharp/exercises/high-scores/solutions/9f55365ea2bb4bf7b70e038002b54a9e) + +## Object-oriented +- Classes: used on the template. +- Encapsulation: used on the template. There are public elements, some people create private elements (especially when non-LINQ approach is used). +- Methods: used on the template; all tested methods needs to be implemented + - methods arguments: constructor receives collection as argument + - return values: returning values from different methods + +## Functional +- Pipelines (LINQ): some solutions use that to process the integer collections. +- Immutability: some people create readonly pre computed collections. +- Anonymous methods: necessary when using LINQ. +- Higher-order functions: when using LINQ - pass methods as arguments to other methods +- Lambda expressions: used when using LINQ +- Expression-bodied members: some solutions include methods written as expression-bodied members +- Enumerables: lists can can be iterated over as an enumerable (using LINQ approach) + +## General +- Generics: use generic collections (lists). +- Enumeration: to process all chars on the string. +- Namespaces: used on the template. +- Exception handling: some people use that to detect errors. Even though it is not required by the tests. +- Nullability: some people need to check for nulls. +- Scoping: use `{` and `}` to denote scoping +- Visibility: making tested method and tested class `public` +- Assignment: assigning values +- Type inference: using `var` to define complex types +- Numbers: signed integers `int` +- Lists: strongly typed lists of `int` objects + +## Approach: Using LINQ +- Enumerable methods for Mapping, Selecting, Ordering: using methods to manipulate enumerables (`LastOrDefault`, `OrderByDescending`, `Take`, `ToList`, `Min`, `Max`) when using LINQ + +## Approach: Using sorted lists +- Enumeration loops (for, foreach): iterate over scores using `for`, `foreach` loops +- Ordering operators:`<`,`<=` +- Math operators: `+`, `+=` within enumeration loops +- Conditionals: Boolean logic operator `&&` +- Indexers: accessing single `int` elements (retrieving scores) From 79796cd834b5ff23d5b89e2f5244fa62a76aef86 Mon Sep 17 00:00:00 2001 From: Pablo Vicente Date: Thu, 20 Feb 2020 19:12:23 +0100 Subject: [PATCH 042/327] Update introduction.md Update introduction.md Co-authored-by: Erik Schierboom --- exercises/concept/strings/.docs/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md index 36b309245c..f8fcac0e4c 100644 --- a/exercises/concept/strings/.docs/introduction.md +++ b/exercises/concept/strings/.docs/introduction.md @@ -1,3 +1,3 @@ # Introduction -A `string` in C# is a sequence of Unicode characters (letters, digits, punctuation, etc.). +A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string. From 1596a15b9dea6cd940ce507feb5aed956d0b97c2 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 21 Feb 2020 12:58:42 +0100 Subject: [PATCH 043/327] Add config.json file to numbers-floating-point exercise --- .../concept/numbers-floating-point/.meta/config.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 exercises/concept/numbers-floating-point/.meta/config.json diff --git a/exercises/concept/numbers-floating-point/.meta/config.json b/exercises/concept/numbers-floating-point/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/numbers-floating-point/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} From c44ad32681f3208c784c7f68d9505b2f0e5a16b3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 21 Feb 2020 11:24:24 +0100 Subject: [PATCH 044/327] Add after document for strings exercise --- exercises/concept/strings/.docs/after.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/exercises/concept/strings/.docs/after.md b/exercises/concept/strings/.docs/after.md index a5354165a8..8a494480e2 100644 --- a/exercises/concept/strings/.docs/after.md +++ b/exercises/concept/strings/.docs/after.md @@ -1,5 +1,17 @@ # After -- The [advanced string interpolation tutorial][tutorial-docs.microsoft.com-string-interpolation] digs deeper into string interpolation. +The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). -[tutorial-docs.microsoft.com-string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +Manipulating a string can be done by calling one of its [methods][methods] or [properties][properties]. As string values can never change after having been defined, all string manipulation methods will return a new string. + +A string is delimited by double quote (`"`) characters. Some special characters need [escaping][escaping] using the backslash (`\`) character. Strings can also be prefixed with the at (`@`) symbol, which makes it a [verbatim string][verbatim] that will ignore any escaped characters. + +Finally, there are [many ways to concatenate a string][concatenation]. The simplest one is by using the [`+` operator][plus-operator]. For any string formatting more complex than simple concatenation, [string interpolation][interpolation] is preferred. To enable interpolation in a string, prefix it with the dollar (`$`) symbol. + +[concatenation]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings +[interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +[verbatim]: https://csharp.net-tutorials.com/data-types/strings/#aelm5298 +[plus-operator]: https://csharp.net-tutorials.com/data-types/strings/#aelm5211 +[escaping]: https://devblogs.microsoft.com/csharpfaq/what-character-escape-sequences-are-available/ +[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#methods +[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#properties From f7401f7753b150e40fe8fc73538bdf3e3801536e Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 21 Feb 2020 17:12:49 +0100 Subject: [PATCH 045/327] Rephrase the design document headers [Docs] Rephrase the design document headers --- exercises/concept/dates/.meta/design.md | 6 ++---- exercises/concept/enums-advanced/.meta/design.md | 6 ++---- exercises/concept/enums/.meta/design.md | 4 ++-- exercises/concept/numbers-floating-point/.meta/design.md | 6 ++---- exercises/concept/numbers/.meta/design.md | 6 ++---- exercises/concept/strings/.meta/design.md | 4 ++-- 6 files changed, 12 insertions(+), 20 deletions(-) diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index 92db0ca965..b3367c1923 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -4,9 +4,7 @@ The goal of this exercise is to teach the student the basics of the Concept of Dates through [C#][docs.microsoft.com-datetime]. -## Things to teach - -After completing this exercise, the student should: +## Learning objectives - Know of the existence of the `DateTime` type. - Know of the individual, date-related properties. @@ -14,7 +12,7 @@ After completing this exercise, the student should: - Know how to compare dates. - Know how to convert a `string` to a `DateTime` and vice versa. -## Things not to teach +## Out of scope - Using standard or custom format strings. - Everything related to timezones. diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/enums-advanced/.meta/design.md index 2ac9ac7b87..10bd3c2968 100644 --- a/exercises/concept/enums-advanced/.meta/design.md +++ b/exercises/concept/enums-advanced/.meta/design.md @@ -4,9 +4,7 @@ The goal of this exercise is to teach the student advanced aspects of the Concept of Enums in [C#][docs.microsoft.com-bitwise-and-shift-operators]. We'll do this in the form of working with [flag][docs.microsoft.com-flagsattribute] enums, which are enums whose values are interpreted as bitwise flags that can be manipulated through bitwise operations. -## Things to teach - -After completing this exercise, the student should: +## Learning objectives - Know what a flags enumeration is. - Know how to define a flags enumeration. @@ -15,7 +13,7 @@ After completing this exercise, the student should: - Know how to unset a flag on an enum value. - Know that an enum's underlying type can be changed. -## Things not to teach +## Out of scope As this is an advanced exercise, there are no enum-related things that we should explicitly _not_ teach. diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index 479bd40442..a6c5987962 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -4,7 +4,7 @@ The goal of this exercise is to teach the student the basics of the Concept of enums through [C#][docs.microsoft.com-enum]. -## Things to teach +## Learning objectives After completing this exercise, the student should: @@ -14,7 +14,7 @@ After completing this exercise, the student should: - Know how to get an enum's numeric value. - Know how to convert a `string` to an `enum` and vice versa. -## Things not to teach +## Out of scope - Flag enums. - That an enum's underlying type can be changed. diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md index 18305c48af..6a6b999cbb 100644 --- a/exercises/concept/numbers-floating-point/.meta/design.md +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -4,15 +4,13 @@ The goal of this exercise is to teach the student how the Concept of floating-point numbers is implemented in [C#][docs.microsoft.com-floating-point-numeric-types]. It will show the available floating-point types and discuss their differences. -## Things to teach - -After completing this exercise, the student should: +## Learning objectives - Know of the existence of the three floating point types: `double`, `float` and `decimal`. - Know when to use which type. - Know how to write a `while` loop. -## Things not to teach +## Out of scope - Parsing floating-point types from strings. - Converting floating-point types to strings. diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index da218611ce..57813d6a63 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -4,9 +4,7 @@ The goal of this exercise is to teach the student how the Concept of Numbers is implemented in [C#][docs.microsoft.com-numbers]. It will introduce this concept through the two most common numeric types in C#: `int` (whole number) and `double` (floating-point number). -## Things to teach - -After completing this exercise, the student should: +## Learning objectives - Know of the existence of the two most commonly used number types, `int` and `double`. - Understand that an `int` represents whole numbers, and a `double` represents floating-point numbers. @@ -14,7 +12,7 @@ After completing this exercise, the student should: - Know how to convert from one numeric type to another; know what implicit and explicit conversions are. - Know how to conditionally execute code using an `if` statement. -## Things not to teach +## Out of scope - Any other numeric types besides `int` and `double` (so no `float`, `byte`, etc.). - Parsing a `string` to an `int` or `double`. diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index ad31dfc01b..cc991ff060 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -4,14 +4,14 @@ The goal of this exercise is to teach the student the basics of the Concept of Strings in [C#][docs.microsoft.com-string]. -## Things to teach +## Learning objectives - Know of the existence of the `string` type. - Know how to create a string. - Know of some basic string methods (like finding the index of a character at a position, or returning a part the string). - Know how to do basic string formatting. -## Things not to teach +## Out of scope - Using standard or custom format strings. - Memory and performance characteristics. From 099f252b6e95a06e81427a2f134a9f0b03056b59 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 22 Feb 2020 21:12:34 +0100 Subject: [PATCH 046/327] Update after.md document for enums exercise --- exercises/concept/enums/.docs/after.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 exercises/concept/enums/.docs/after.md diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md new file mode 100644 index 0000000000..87bea22d11 --- /dev/null +++ b/exercises/concept/enums/.docs/after.md @@ -0,0 +1,19 @@ +# After + +Whenever you have a fixed set of constant values, an `enum` can be used. Using an enum gives one a type-safe way of interacting with constant values. + +Another benefit of enums are that they are very declarative. Compare the following two pieces of code: + +```csharp +Users.WithStatus(1) +``` + +vs + +```csharp +Users.WithStatus(Status.Active) +``` + +For someone reading the code, the second (enum) version will be easier to comprehend. + +You should always consider using an enum whenever you want to model something as a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof. From ea7aea41a18331a845a253a02e68f2230f168179 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 22 Feb 2020 21:33:44 +0100 Subject: [PATCH 047/327] Update after.md document for enums-advanced exercise --- exercises/concept/enums-advanced/.docs/after.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/enums-advanced/.docs/after.md index a439989286..73e8b2eb31 100644 --- a/exercises/concept/enums-advanced/.docs/after.md +++ b/exercises/concept/enums-advanced/.docs/after.md @@ -1,7 +1,8 @@ # After -- [Working with enums as bit flags][docs.microsoft.com-enumeration-types-as-bit-flags]. -- [Enum flags and bitwise operators][alanzucconi.com-enum-flags-and-bitwise-operators]. +To allow an enum value to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By assigning the values of the enum such that each values has exactly one bit set to `1`, bitwise operators can be used to set or unset flags. + +The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. [docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ From 95a57e1b76dcc03ba167f22101a6b1b80575f9fb Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 21 Feb 2020 14:34:30 +0100 Subject: [PATCH 048/327] Update after.md document for dates exercise --- exercises/concept/dates/.docs/after.md | 4 ++-- exercises/concept/dates/.meta/design.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/exercises/concept/dates/.docs/after.md b/exercises/concept/dates/.docs/after.md index 65d47978cc..0b261c0549 100644 --- a/exercises/concept/dates/.docs/after.md +++ b/exercises/concept/dates/.docs/after.md @@ -1,5 +1,5 @@ # After -- Interpolated strings support [specifying format strings][docs.microsoft.com_specify-a-format-string-for-an-interpolation-expression] for their interpolated values. +In C# dates are represented as `DateTime` instances, which contains both date _and_ time information. Dates can be compared using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the static `DateTime.Now` property. -[docs.microsoft.com_specify-a-format-string-for-an-interpolation-expression]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation#how-to-specify-a-format-string-for-an-interpolation-expression +An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s (either as input or output) will be dependent on the current culture. diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index b3367c1923..4e5ff8d393 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -7,6 +7,7 @@ The goal of this exercise is to teach the student the basics of the Concept of D ## Learning objectives - Know of the existence of the `DateTime` type. +- Know how to get the current date. - Know of the individual, date-related properties. - Know how to access the current date. - Know how to compare dates. From e701e33df93d5ee7d8b906646968847fe294b06a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 21 Feb 2020 15:44:39 +0100 Subject: [PATCH 049/327] Update after.md document for numbers-floating-point exercise --- .../concept/numbers-floating-point/.docs/after.md | 12 +++++++----- .../numbers-floating-point/.docs/introduction.md | 4 ++-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md index 357316236e..e223af9a00 100644 --- a/exercises/concept/numbers-floating-point/.docs/after.md +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -1,14 +1,16 @@ # After -- See the [characteristics of the floating-point types table][docs-microsoft.com-characteristics-of-the-floating-point-types] for an overview of the precision, approximate range and size of the three floating-point types. +There are three floating-point types in C#: `float`, `double` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. -- Converting between numeric types is sometimes [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but at other times [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. +Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. -- Be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. +Some conversions between floating point types are [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but others are [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. -- You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. +Always be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. -- The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. +You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. + +To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `true`. [docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions [docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/numbers-floating-point/.docs/introduction.md index a77ccf10c3..f8d56a61bb 100644 --- a/exercises/concept/numbers-floating-point/.docs/introduction.md +++ b/exercises/concept/numbers-floating-point/.docs/introduction.md @@ -4,7 +4,7 @@ A floating-point number is a number with zero or more digits behind the decimal Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision. -C# has three floating point types: +C# has three floating-point types: - `float`: 4 bytes (~6-9 digits precision). Written as `2.45f`. - `double`: 8 bytes (~15-17 digits precision). This is the most common type. Written as `2.45` or `2.45d`. @@ -12,4 +12,4 @@ C# has three floating point types: As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded). -In this exercise you may also want to use a loop. There are several ways to write loops in C#, the most common ones being `while` and `for` loops. +In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here. From ad44caf26358364d3f34b5855c4aa8bec6441270 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 25 Feb 2020 22:07:12 +0100 Subject: [PATCH 050/327] C#] Update after.md document for numbers exercise ] Update after.md document for numbers exercise * Update languages/exercises/concept/numbers/.docs/after.md Co-Authored-By: Rob Keim Co-authored-by: Rob Keim --- exercises/concept/numbers/.docs/after.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 exercises/concept/numbers/.docs/after.md diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md new file mode 100644 index 0000000000..5aec188300 --- /dev/null +++ b/exercises/concept/numbers/.docs/after.md @@ -0,0 +1,14 @@ +# After + +One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). + +The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). + +Numbers can be compared using the default comparison operators (`<`, `>`, `==`, etc.). These operators can be used in `if` statements to conditionally execute code. + +When converting between numeric types, there are two types of numeric conversions: + +1. Implicit conversions: no data will be lost and no additional syntax is required. +2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. + +As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. From f52b0fc105a8c25b02dde63948fd5e08409a22c0 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 26 Feb 2020 13:24:00 +0100 Subject: [PATCH 051/327] Use student instead of user --- reference/exercise-concepts/nucleotide-count.md | 2 +- reference/exercise-concepts/space-age.md | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/reference/exercise-concepts/nucleotide-count.md b/reference/exercise-concepts/nucleotide-count.md index 90e51bc0fa..23c6695f29 100644 --- a/reference/exercise-concepts/nucleotide-count.md +++ b/reference/exercise-concepts/nucleotide-count.md @@ -46,4 +46,4 @@ ## Notes -- Having the exercise return an `IDictionary` means that the users will have to know about interfaces too. This was not the goal of the exercise (teaching about dictionaries is), so it's interesting to see that this was missed. Good thing to keep in mind when developing Concept Exercises. +- Having the exercise return an `IDictionary` means that the students will have to know about interfaces too. This was not the goal of the exercise (teaching about dictionaries is), so it's interesting to see that this was missed. Good thing to keep in mind when developing Concept Exercises. diff --git a/reference/exercise-concepts/space-age.md b/reference/exercise-concepts/space-age.md index 2970431793..2f49f4302f 100644 --- a/reference/exercise-concepts/space-age.md +++ b/reference/exercise-concepts/space-age.md @@ -3,24 +3,27 @@ [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/space-age/Example.cs) ## General + - methods: used as the entry points to this exercise - class: the tested methods are defined in a class - class constructor: SpaceAge class uses a constructor to assign the amount of seconds - visibility: making tested method and tested class `public` while making class members which contain data `private` - imports: import types through `using` statements -- expression-bodied members: it makes the code cleaner for On{Planet} methods -- double: the return value of the On{Planet} methods and the argument of the class constructor is of type double, meaning the user must be exposed to working with floating point numbers -- division operator: user must know how to use binary arithmetic operators +- expression-bodied members: it makes the code cleaner for On{Planet} methods +- double: the return value of the On{Planet} methods and the argument of the class constructor is of type double, meaning the student must be exposed to working with floating point numbers +- division operator: student must know how to use binary arithmetic operators ## Approach using constants + - const: each orbital period for a planet can be stored into a constant field to prevent modification of the values ## Approach using Dictionary class + - using: import proper namespace for access to the Dictionary Class (System.Collections.Generic) - dictionaries : use the Dictionary class to store factors on each planet - object initializers: create a dictionary with proper type for keys and values, assign proper combinations of key-value pairs - indexers: used to retrieve values by their specified keys ## Approach using Enums -- enum: can be used as a Key for the Dictionary class instead of a string +- enum: can be used as a Key for the Dictionary class instead of a string From 0caf2bb9ca0b4ea9d261bbffa4c736a7e93cb01c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 26 Feb 2020 13:35:25 +0100 Subject: [PATCH 052/327] Remove primary heading for documents in `.docs` folder --- exercises/concept/dates/.docs/after.md | 2 -- exercises/concept/dates/.docs/hints.md | 2 -- exercises/concept/dates/.docs/instructions.md | 2 -- exercises/concept/dates/.docs/introduction.md | 2 -- exercises/concept/enums-advanced/.docs/after.md | 2 -- exercises/concept/enums-advanced/.docs/hints.md | 2 -- exercises/concept/enums-advanced/.docs/instructions.md | 2 -- exercises/concept/enums-advanced/.docs/introduction.md | 2 -- exercises/concept/enums/.docs/after.md | 2 -- exercises/concept/enums/.docs/hints.md | 2 -- exercises/concept/enums/.docs/instructions.md | 2 -- exercises/concept/enums/.docs/introduction.md | 2 -- exercises/concept/numbers-floating-point/.docs/after.md | 2 -- exercises/concept/numbers-floating-point/.docs/hints.md | 2 -- exercises/concept/numbers-floating-point/.docs/instructions.md | 2 -- exercises/concept/numbers-floating-point/.docs/introduction.md | 2 -- exercises/concept/numbers/.docs/after.md | 2 -- exercises/concept/numbers/.docs/hints.md | 2 -- exercises/concept/numbers/.docs/instructions.md | 2 -- exercises/concept/numbers/.docs/introduction.md | 2 -- exercises/concept/strings/.docs/after.md | 2 -- exercises/concept/strings/.docs/hints.md | 2 -- exercises/concept/strings/.docs/instructions.md | 2 -- exercises/concept/strings/.docs/introduction.md | 2 -- 24 files changed, 48 deletions(-) diff --git a/exercises/concept/dates/.docs/after.md b/exercises/concept/dates/.docs/after.md index 0b261c0549..d7e8d50a2c 100644 --- a/exercises/concept/dates/.docs/after.md +++ b/exercises/concept/dates/.docs/after.md @@ -1,5 +1,3 @@ -# After - In C# dates are represented as `DateTime` instances, which contains both date _and_ time information. Dates can be compared using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the static `DateTime.Now` property. An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s (either as input or output) will be dependent on the current culture. diff --git a/exercises/concept/dates/.docs/hints.md b/exercises/concept/dates/.docs/hints.md index 41dfaf0073..a71cdb7ff4 100644 --- a/exercises/concept/dates/.docs/hints.md +++ b/exercises/concept/dates/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### General - [Tutorial on dates and time by csharp.net][csharp.net-dates-working-with-dates-time] diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md index 0bceca05da..3e17d114e2 100644 --- a/exercises/concept/dates/.docs/instructions.md +++ b/exercises/concept/dates/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be working on an appointment scheduler for a beauty salon in New York. You have four tasks, which will all involve appointment dates. The dates and times will use one of the following four formats: diff --git a/exercises/concept/dates/.docs/introduction.md b/exercises/concept/dates/.docs/introduction.md index 1d2564fea8..63a3fed691 100644 --- a/exercises/concept/dates/.docs/introduction.md +++ b/exercises/concept/dates/.docs/introduction.md @@ -1,5 +1,3 @@ -# Introduction - The C# `DateTime` type is a type that contains both date and time information. The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`. diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/enums-advanced/.docs/after.md index 73e8b2eb31..a1251c17ad 100644 --- a/exercises/concept/enums-advanced/.docs/after.md +++ b/exercises/concept/enums-advanced/.docs/after.md @@ -1,5 +1,3 @@ -# After - To allow an enum value to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By assigning the values of the enum such that each values has exactly one bit set to `1`, bitwise operators can be used to set or unset flags. The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. diff --git a/exercises/concept/enums-advanced/.docs/hints.md b/exercises/concept/enums-advanced/.docs/hints.md index b1acd1216c..64597fe918 100644 --- a/exercises/concept/enums-advanced/.docs/hints.md +++ b/exercises/concept/enums-advanced/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### 1. Get default permissions for an account type - To handle each account type, one could use an `if` statement, but the [`switch` statement][docs.microsoft.com-switch-keyword] is a great alternative. diff --git a/exercises/concept/enums-advanced/.docs/instructions.md b/exercises/concept/enums-advanced/.docs/instructions.md index 28c3f78df4..35fcf8ae89 100644 --- a/exercises/concept/enums-advanced/.docs/instructions.md +++ b/exercises/concept/enums-advanced/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be checking permissions of user accounts on an internet forum. The forum supports three different permissions: - Read diff --git a/exercises/concept/enums-advanced/.docs/introduction.md b/exercises/concept/enums-advanced/.docs/introduction.md index fe79fe7445..ee57fa51ea 100644 --- a/exercises/concept/enums-advanced/.docs/introduction.md +++ b/exercises/concept/enums-advanced/.docs/introduction.md @@ -1,3 +1 @@ -# Introduction - The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can mark the `enum` as one which constants are _flags_. By carefully assigning the values of each constant, one can use bitwise operators to add or remove references to one or more of the (flag) constants. diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md index 87bea22d11..d06b4a09b0 100644 --- a/exercises/concept/enums/.docs/after.md +++ b/exercises/concept/enums/.docs/after.md @@ -1,5 +1,3 @@ -# After - Whenever you have a fixed set of constant values, an `enum` can be used. Using an enum gives one a type-safe way of interacting with constant values. Another benefit of enums are that they are very declarative. Compare the following two pieces of code: diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/enums/.docs/hints.md index 7f495cb19a..5098aa77c0 100644 --- a/exercises/concept/enums/.docs/hints.md +++ b/exercises/concept/enums/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### General - [Tutorial on working with enums][docs.microsoft.com-enumeration-types]. diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index a34b97cf70..1bdb2880b6 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be processing log-lines. Each log line is a string formatted as follows: `"[]: "`. diff --git a/exercises/concept/enums/.docs/introduction.md b/exercises/concept/enums/.docs/introduction.md index 3121166b9e..90f298c775 100644 --- a/exercises/concept/enums/.docs/introduction.md +++ b/exercises/concept/enums/.docs/introduction.md @@ -1,3 +1 @@ -# Introduction - The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md index e223af9a00..1de731ae8e 100644 --- a/exercises/concept/numbers-floating-point/.docs/after.md +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -1,5 +1,3 @@ -# After - There are three floating-point types in C#: `float`, `double` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/numbers-floating-point/.docs/hints.md index f4448a5e71..2ef80f29a2 100644 --- a/exercises/concept/numbers-floating-point/.docs/hints.md +++ b/exercises/concept/numbers-floating-point/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### General - [Floating-point numeric types introduction][docs.microsoft.com-floating_point_numeric_types]. diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/numbers-floating-point/.docs/instructions.md index 6ef0972949..e24d8abfab 100644 --- a/exercises/concept/numbers-floating-point/.docs/instructions.md +++ b/exercises/concept/numbers-floating-point/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be working with savings accounts. Each year, the balance of each savings account is updated based on the [annual percentage yield][wikipedia-annual_percentage_yield] (APY). The APY value depends on the amount of money in the account (its balance): - -3.213% for a negative balance. diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/numbers-floating-point/.docs/introduction.md index f8d56a61bb..891554f6e8 100644 --- a/exercises/concept/numbers-floating-point/.docs/introduction.md +++ b/exercises/concept/numbers-floating-point/.docs/introduction.md @@ -1,5 +1,3 @@ -# Introduction - A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision. diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md index 5aec188300..2d9ed01ae0 100644 --- a/exercises/concept/numbers/.docs/after.md +++ b/exercises/concept/numbers/.docs/after.md @@ -1,5 +1,3 @@ -# After - One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md index 94df0c6a0c..b70f927abd 100644 --- a/exercises/concept/numbers/.docs/hints.md +++ b/exercises/concept/numbers/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### General - [docs.microsoft.com numbers tutorial][tutorial-docs.microsoft-numbers] diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index b91a4d9b81..f2a0eb1991 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be writing code to analyze the production of an assembly line in a car factory. The assembly line's speed can range from `0` (off) to `10` (maximum). At its lowest speed (`1`), `221` cars are produced each hour. The production increases linearly with the speed. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate: diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index d6b98469bf..dc3008c511 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -1,5 +1,3 @@ -# Introduction - There are two different types of numbers in C#: - Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. diff --git a/exercises/concept/strings/.docs/after.md b/exercises/concept/strings/.docs/after.md index 8a494480e2..5d7575c7c0 100644 --- a/exercises/concept/strings/.docs/after.md +++ b/exercises/concept/strings/.docs/after.md @@ -1,5 +1,3 @@ -# After - The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Manipulating a string can be done by calling one of its [methods][methods] or [properties][properties]. As string values can never change after having been defined, all string manipulation methods will return a new string. diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/strings/.docs/hints.md index 1c5a2e9368..7cf72c7dcc 100644 --- a/exercises/concept/strings/.docs/hints.md +++ b/exercises/concept/strings/.docs/hints.md @@ -1,5 +1,3 @@ -# Hints - ### General - The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction C# `string`'s. diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index 4d53521267..5d7c73c672 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -1,5 +1,3 @@ -# Instructions - In this exercise you'll be processing log-lines. Each log line is a string formatted as follows: `"[]: "`. diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md index f8fcac0e4c..335f05b7ea 100644 --- a/exercises/concept/strings/.docs/introduction.md +++ b/exercises/concept/strings/.docs/introduction.md @@ -1,3 +1 @@ -# Introduction - A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string. From 5d69634c802891f6988160e62f3b314a2030ea64 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 26 Feb 2020 16:35:03 +0100 Subject: [PATCH 053/327] Add docs/reference split * [Docs] Move implementing-a-concept-exercise.md to reference folder * [Docs] Move reference documents to docs folder * [Docs] Update to student-facing docs * [Docs] Add new issue template Co-Authored-By: Jeremy Walker Co-Authored-By: Victor Goff Co-authored-by: Sascha Mann --- reference/code_style.md | 49 ----- .../examples/new-concept-exercise-arrays.md | 194 ++++++++++++++++++ .../new-reference-doc-readonly-vs-const.md | 33 +++ reference/implementing-a-concept-exercise.md | 68 ++++++ reference/memory_allocation.md | 28 --- reference/out-of-scope.md | 20 +- 6 files changed, 307 insertions(+), 85 deletions(-) delete mode 100644 reference/code_style.md create mode 100644 reference/examples/new-concept-exercise-arrays.md create mode 100644 reference/examples/new-reference-doc-readonly-vs-const.md create mode 100644 reference/implementing-a-concept-exercise.md delete mode 100644 reference/memory_allocation.md diff --git a/reference/code_style.md b/reference/code_style.md deleted file mode 100644 index 59ad5be88d..0000000000 --- a/reference/code_style.md +++ /dev/null @@ -1,49 +0,0 @@ -# Code style - -While the C# compiler doesn't enforce a particular code style, there are general [coding conventions][docs.microsoft.com_coding-conventions] and [design guidelines][docs.microsoft.com_design-guidelines]. - -## Formatting conventions - -The C# formatting formatting conventions are defined in the [layout conventions][docs.microsoft.com_layout-conventions]. - -## Naming conventions - -Broadly speaking, the C# naming conventions are as follows: - -- PascalCase for types, methods and constants. -- camelCase for fields, variables and parameters. - -These conventions are described in the [.NET capitalization conventions][docs.microsoft.com_capitalization-conventions] and the [.NET general naming conventions][docs.microsoft.com_general-naming-conventions]. - -## Other conventions - -### Prefer type alias - -The general consensus is to prefer the C# type over the .NET type. Here are some examples where this prefererence shows: - -- The default [C# editorconfig settings][docs.microsoft.com_editorconfig-language-keywords]. -- The [ReSharper built-in type naming rule][jetbrains.com_built-in-type-naming]. -- The [CoreFX coding style document][github.com_corefx-coding-style]. - -## Enforcing code style - -It is possible to encode C# coding style conventions using [`.editorconfig files`][docs.microsoft.com_editorconfig]. This includes being able to specify [formatting conventions][docs.microsoft.com_editorconfig-formatting-conventions] and [naming conventions][docs.microsoft.com_editorconfig-naming-conventions]. - -Most C# IDE's have support for `.editorconfig` files, including Visual Studio 2019+, Rider and VS Code (using the C# extension). - -The [dotnet format global tool][github.com_dotnet-format-editorconfig-options] can be run as a [command-line tool][github.com_dotnet-format-how-to] and has support for a [limited set of the `.editorconfig` settings][github.com_dotnet-format-editorconfig-options]. - -[docs.microsoft.com_design-guidelines]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/ -[docs.microsoft.com_coding-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions -[docs.microsoft.com_capitalization-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions -[docs.microsoft.com_general-naming-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions -[docs.microsoft.com_layout-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions#layout-conventions -[docs.microsoft.com_editorconfig]: https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2019 -[docs.microsoft.com_editorconfig-formatting-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions?view=vs-2019 -[docs.microsoft.com_editorconfig-naming-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions?view=vs-2019 -[github.com_dotnet-format]: https://github.com/dotnet/format/blob/master/README.md -[github.com_dotnet-format-editorconfig-options]: https://github.com/dotnet/format/wiki/Supported-.editorconfig-options -[github.com_dotnet-format-how-to]: https://github.com/dotnet/format/blob/master/README.md#how-to-install -[docs.microsoft.com_editorconfig-language-keywords]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#language-keywords -[github.com_corefx-coding-style]: https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md -[jetbrains.com_built-in-type-naming]: https://www.jetbrains.com/help/resharper/Built_In_Type_Naming.html diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md new file mode 100644 index 0000000000..47124aec2e --- /dev/null +++ b/reference/examples/new-concept-exercise-arrays.md @@ -0,0 +1,194 @@ +# [C#] Add new Concept Exercise - arrays + +This issue describes a new `arrays` exercise that should be added to the [v3 C# track][csharp-docs]. + +## Goal + +The goal of this exercise is to teach the student how the concept of [collections][docs-v3-types-collection] is implemented in [C#][docs.microsoft.com-collections]. We'll teach the student about collections by having the student work with one specific type of collection, namely the [array][docs-v3-types-array]. The students will learn to define arrays, iterate over array items, access items by index, and more. + +Of the many available C# collection types, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons: + +- Arrays don't require the student to know about generics. +- Arrays are a common data type in many language. +- Arrays have a fixed length. No complexity in adding or removing elements. +- Arrays have a simple shorthand syntax. No need to understand how constructors work to define an array. + +## Learning objectives + +- Know of the existence of the `Array` type. +- Know how to define an array. +- Know how to access elements in an array by index. +- Know how to iterate over elements in an array. +- Know some basic array functions (like finding the index of an element in an array). + +## Out of scope + +- Multi-dimensional/jagged arrays. +- Memory and performance characteristics of arrays. +- Enumerables. +- Iterators. +- LINQ. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `collections-basic`: know how to iterate over a collection. +- `arrays-basic`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). + +## Prequisites + +As an array is a collection type, it holds zero or more instances of another type. That means it _has_ to depend on one or more other types. In this exercise, we'll use the `int` data type for that, which is both interesting enough and easy to work with. The `int` data type is introduced in the `numbers-basic` concept. + +This Concept Exercise's prerequisites Concepts are: + +- `numbers-basic`: `int` values will be stored in the array and returned as output. + +## Resources to refer to + +### Hints + +- [Arrays][docs.microsoft.com-arrays] +- [Single-dimensional arrays][docs.microsoft.com-single-dimensional-arrays] +- [Usings foreach with arrays][docs.microsoft.com-foreach-with-arrays] + +### After + +- [Collections][docs.microsoft.com-collections] +- [Implicitly typed arrays][docs.microsoft.com-implicitly-typed-arrays] + +As this is an introductory exercise, we should take care not to link to very advanced resources, to prevent overwhelming the student. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][csharp-representer]. + +## Analyzer + +This exercise could benefit from having an [analyzer][csharp-analyzer] that can comment on: + +- Difference between `for` vs `foreach` loops. + +## Implementing + +If you'd like to work on implementing this exercise, the first step is to let us know through a comment on this issue, to prevent multiple people from working on the same exercise. If you have any questions while implementing the exercise, please also post them as comments in this issue. + +Implementing the exercise means creating the following files: + +
+languages
+└── csharp
+    └── exercises
+        └── concept
+            └── arrays
+                ├── .docs
+                |   ├── after.md
+                |   ├── hints.md
+                |   ├── instructions.md
+                |   └── introduction.md
+                ├── .meta
+                |   ├── config.json
+                |   ├── design.md
+                |   └── Example.cs
+                ├── Arrays.csproj
+                ├── Arrays.cs
+                └── ArraysTest.cs
+
+ +## Step 1: add .docs/introduction.md + +This file contains an introduction to the concept. It should be explicit about what the student should learn from the exercise, and provide a short, concise introduction to the concept(s). The aim is to give the student just enough context to figure things out themselves and solve the exercise, as research has shown that self-discovery is the most effective learning experience. Mentioning technical terms that the student can Google if they so want, is preferable over including any code samples or an extensive description. For example we might describe a string as a "Sequence of Unicode characters" or a "series of bytes" or "an object". Unless the student needs to understand the details of what those mean to be able to solve the exercise we should not give more info in this introduction - instead allowing the student to Google, ignore, or map their existing knowledge. + +## Step 2: add .docs/instructions.md + +This file contains instructions for the exercise. It should explicitly explain what the student needs to do (define a method with the signature `X(...)` that takes an A and returns a Z), and provide at least one example usage of that function. If there are multiple tasks within the exercise, it should provide an example of each. + +## Step 3: add .docs/hints.md + +If the student gets stuck, we will allow them to click a button requesting a hint, which shows this file. This will not be a "recommended" path and we will (softly) discourage them using it unless they can't progress without it. As such, it's worth considering that the student reading it will be a little confused/overwhelmed and maybe frustrated. + +The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student. They might link to the docs of the functions that need to be used. + +## Step 4: add .docs/after.md + +Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. + +The above four files are also all described in the [concept exercises document][docs-concept-exercises]. + +## Step 5: update languages/csharp/config.json + +An entry should be added to the track's `config.json` file for the new concept exercise: + +```json +{ + ... + "exercises": { + "concept": [ + ... + { + "slug": "arrays", + "uuid": "b6c532c9-1e89-4fbf-8f08-27f5befb5bb8", + "concepts": ["collections-basic", "arrays-basic"], + "prerequisites": ["numbers-basic"] + } + ] + } +} +``` + +## Step 6: adding track-specific files + +These files are specific to the C# track: + +- `Arrays.csproj`: the C# project file. +- `ArraysTest.cs`: the test suite. +- `Arrays.cs`. the stub implementation file, which is the starting point for students to work on the exercise. +- `.meta/Example.cs`: an example implementation that passes all the tests. + +Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-floating-point-numbers] for an example on what these files should look like. + +## Step 7: update the general concept document + +Add the exercise to the [concept's shared document's][referrence-array] `## Implementations` section ([example](https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations)). + +## Step 8: updating list of implemented exercises + +- Add the exercise to the [list of implemented exercises][csharp-docs-concept-exercises]. + +## Step 9: add .meta/design.md: + +This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][meta-design]). This information can be extracted from this GitHub issue. + +## Step 10: add .meta/config.json: + +This file contains meta information on the exercise, which currently only includes the exercise's contributors ([example][meta-config.json]). + +### Inspiration + +When implementing this exericse, it can be very useful to look at already implemented C# exercises like the [strings][csharp-docs-concept-exercises-strings], [dates][csharp-docs-concept-exercises-dates] or [floating-point numbers][csharp-docs-concept-exercises-floating-point-numbers] exercises. You can also check the [general array concept documentation][docs-v3-types-array] to see if any other languages have already implemented an arrays exercise. + +[docs.microsoft.com-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/ +[docs.microsoft.com-collections]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections +[docs.microsoft.com-foreach-with-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[docs.microsoft.com-single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[docs.microsoft.com-implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[docs-v3]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md#exercise-structure +[docs-v3-types-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md +[docs-v3-types-collection]: https://github.com/exercism/v3/blob/master/reference/types/collection.md +[csharp-docs]: https://github.com/exercism/v3/blob/master/languages/csharp/README.md +[csharp-docs-concept-exercises-strings]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/strings +[csharp-docs-concept-exercises-dates]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates +[csharp-docs-concept-exercises-floating-point-numbers]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[csharp-analyzer]: https://github.com/exercism/csharp-analyzer +[csharp-representer]: https://github.com/exercism/csharp-representer +[csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md +[csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md +[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/after.md +[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/hints.md +[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/introduction.md +[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/instructions.md +[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/design.md +[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.meta/config.json +[csharp-docs-concept-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md +[referrence-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md +[meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/enums-advanced/.meta/config.json diff --git a/reference/examples/new-reference-doc-readonly-vs-const.md b/reference/examples/new-reference-doc-readonly-vs-const.md new file mode 100644 index 0000000000..c5b14282d2 --- /dev/null +++ b/reference/examples/new-reference-doc-readonly-vs-const.md @@ -0,0 +1,33 @@ +# [C#] Add new reference document: readonly vs const + +This issue describes how to add a new [C# reference document][reference]: readonly vs const. + +## Description + +The goal of the new reference document is to explain the different between (`static`) `readonly` fields versus `const` fields, which is confusing to many students. + +The document should explain how the two approaches are different, taking into account: + +- What values they can be applied to. +- Readability aspects. +- Performance characteristics. +- Memory aspects. +- Generated IL code (optional). + +Based on the aforementioned differences, the document should provide guidance on when to use which approach and why. + +## Resources to refer to + +- [StackOverflow - static readonly vs const][stackoverflow.com] + +## Contributing + +To create the reference, please: + +- [Create the document at `language/csharp/reference/readonly-vs-const.md`][new-document]. +- Remove the corresponding TODO item in the [reference README][reference]. +- Add a link to the reference document in the [reference README][reference]. + +[stackoverflow.com]: https://stackoverflow.com/questions/755685/static-readonly-vs-const#755693 +[reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs +[new-document]: https://github.com/exercism/v3/new/master?filename=languages/csharp/reference/readonly-vs-const.md diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md new file mode 100644 index 0000000000..0cdbd0a57d --- /dev/null +++ b/reference/implementing-a-concept-exercise.md @@ -0,0 +1,68 @@ +# How to implement a C# concept exercise + +This document describes how to implement a concept exercise for the C# track. As this document is generic, the following placeholders are used: + +- ``: the name of the exercise in kebab-case (e.g. `anonymous-methods`). +- ``: the name of the exercise in PascalCase (e.g. `AnonymousMethods`). + +Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what not). This information can be found in the exercise's GitHub issue. Having done this, please read the [C# concept exercises introduction][concept-exercises]. + +To implement a concept exercise, the following files must be created: + +
+languages
+└── csharp
+    └── exercises
+        └── concept
+            └── <SLUG>
+                ├── .docs
+                |   ├── instructions.md
+                |   ├── introduction.md
+                |   ├── hints.md
+                |   └── after.md (optional)
+                ├── .meta
+                |   |── config.json
+                |   |── design.md
+                |   └── Example.cs
+                ├── <NAME>.cs
+                ├── <NAME>.csproj
+                └── <NAME>Test.cs
+
+ +## Step 1: adding track-specific files + +These files are specific to the C# track: + +- `.cs`. the stub implementation file, which is the starting point for students to work on the exercise. +- `.csproj`: the C# project file. +- `Test.cs`: the test suite. +- `.meta/Example.cs`: an example implementation that passes all the tests. + +## Step 2: adding common files + +How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. + +## Step 3: add analyzer (optional) + +Some exercises could benefit from having an exercise-specific [analyzer][analyzer]. If so, specify what analysis rules should be applied to this exercise and why. + +## Step 4: custom representation (optional) + +Some exercises could benefit from having an custom representation as generated by the [C# representer][representer]. If so, specify what changes to the representation should be applied and why. + +## Inspiration + +When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [dates][concept-exercise-dates] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. + +## Help + +If you have any questions regarding implementing the exercise, please post them as comments in the exercise's GitHub issue. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[concept-exercises]: ../exercises/concept/README.md +[how-to-implement-a-concept-exercise]: ../../../docs/maintainers/generic-how-to-implement-a-concept-exercise.md +[concept-exercise-strings]: ../exercises/concept/strings +[concept-exercise-dates]: ../exercises/concept/dates +[concept-exercise-numbers-floating-point]: ../exercises/concept/numbers-floating-point +[reference]: ../../../reference diff --git a/reference/memory_allocation.md b/reference/memory_allocation.md deleted file mode 100644 index 81e4fbe7f4..0000000000 --- a/reference/memory_allocation.md +++ /dev/null @@ -1,28 +0,0 @@ -# Memory allocation - -The important thing about allocating memory in C# is that it is done _automatically_; there is no need to manually allocate memory. To allow the automatic memory to also be deallocated when it is no longer used, C# uses a [garbage collector][docs.microsoft.com_garbage-collection-fundamentals]. - -There are two different types of memory used when working with C#: - -- The stack. -- The heap. - -The stack is short-lived and has limited space available. Exceeding the maximum amount of allowed memory of the stack results in a `StackOverflowException` being thrown. Each thread has its own stack. As the stack is automatically "unwinded" after a method returns, there is no need for the garbage collector to be involved. This means that (de)allocating memory on the stack is very fast. - -The heap is long-lived and has lots of memory available. When an object is allocated, the memory allocator will find some free memory on the heap and allocate it. The heap is shared between threads and can be used to share data. Once every while, the garbage collector will halt execution (a "GC pause") and check if there are objects that are no longer being used. If so, the memory for these objects will be deallocated and their memory will become available for later allocation again. - -## What goes where? - -In principle, value types are allocated on the stack and reference types on the heap. There are some exceptions to this, for example when a value type is part of a reference type (e.g. a class with an `int` field). - -## Resources - -- [Garbage collection fundamentals][docs.microsoft.com_garbage-collection-fundamentals] -- [Jetbrains memory management concepts][jetbrains.com_memory-management-concepts] -- [Jon skeet on C# memory allocation][jonskeet.uk_memory] -- [Pro .NET memory management (book)][pro-dotnet-memory] - -[docs.microsoft.com_garbage-collection-fundamentals]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals -[jonskeet.uk_memory]: https://jonskeet.uk/csharp/memory.html -[jetbrains.com_memory-management-concepts]: https://www.jetbrains.com/help/dotmemory/NET_Memory_Management_Concepts.html -[pro-dotnet-memory]: https://prodotnetmemory.com/ diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md index 2f4132a0bc..dae4d22e7c 100644 --- a/reference/out-of-scope.md +++ b/reference/out-of-scope.md @@ -1,36 +1,40 @@ # Topics Falling Outside of the Scope of Exercism's C# Track This document provides examples of material that falls outside of -Exercism's scope. It indicates the limits of what can be +Exercism's scope. It indicates the limits of what can be directly taught by the exercises. -The document should answer the question -"Is topic or skill x covered by Exercism?". +The document should answer the question +"Is topic or skill x covered by Exercism?". -The material should be capable of being communicated to an enquiring +The material should be capable of being communicated to an enquiring student as and when required. -Where material is covered under "What not to teach" in _design.md_ +Where material is covered under "What not to teach" in _design.md_ for a particular exercise it should not be repeated here unless it is felt that the topic otherwise has insufficient prominence. ### 3rd Party and Microsoft Libraries + - JSON.net - NodaTime - .NET Forms - WPF -### Frameworks +### Frameworks + - .NET Framework - ASP.NET (Core) - Unity -### Platform +### Platform + - .NET interop (e.g. with Visual Basic or F#) - NuGet - Project/solution files ### Other + - File handling - Networking -- Compiler directives \ No newline at end of file +- Compiler directives From 97b07d84c8732e0b884550b1eeccc6ec2d6a52f6 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 26 Feb 2020 20:18:01 +0100 Subject: [PATCH 054/327] Update framework and packages --- exercises/concept/dates/Dates.csproj | 4 ++-- exercises/concept/enums-advanced/EnumsAdvanced.csproj | 4 ++-- exercises/concept/enums/Enums.csproj | 4 ++-- .../numbers-floating-point/NumbersFloatingPoint.csproj | 4 ++-- exercises/concept/numbers/Numbers.csproj | 4 ++-- exercises/concept/strings/Strings.csproj | 4 ++-- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/exercises/concept/dates/Dates.csproj b/exercises/concept/dates/Dates.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/dates/Dates.csproj +++ b/exercises/concept/dates/Dates.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + diff --git a/exercises/concept/enums-advanced/EnumsAdvanced.csproj b/exercises/concept/enums-advanced/EnumsAdvanced.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/enums-advanced/EnumsAdvanced.csproj +++ b/exercises/concept/enums-advanced/EnumsAdvanced.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + diff --git a/exercises/concept/enums/Enums.csproj b/exercises/concept/enums/Enums.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/enums/Enums.csproj +++ b/exercises/concept/enums/Enums.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + diff --git a/exercises/concept/numbers/Numbers.csproj b/exercises/concept/numbers/Numbers.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/numbers/Numbers.csproj +++ b/exercises/concept/numbers/Numbers.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + diff --git a/exercises/concept/strings/Strings.csproj b/exercises/concept/strings/Strings.csproj index e4ae56cdd6..cfef7a3e96 100644 --- a/exercises/concept/strings/Strings.csproj +++ b/exercises/concept/strings/Strings.csproj @@ -1,11 +1,11 @@  - netcoreapp3.0 + netcoreapp3.1 - + From 869923e3d3a1d3a15d4fe18327d7ea4057d4324a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 27 Feb 2020 14:01:58 +0100 Subject: [PATCH 055/327] Add no-code part to hints.md --- reference/examples/new-concept-exercise-arrays.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index 47124aec2e..e86138d3f9 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -109,6 +109,8 @@ If the student gets stuck, we will allow them to click a button requesting a hin The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student. They might link to the docs of the functions that need to be used. +The hints should not spell out the solution, but instead point to a resource describing the solution (e.g. linking to documentation for the function to use). + ## Step 4: add .docs/after.md Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. From ca274e7f1a012ccf19d37f97dff60742e65411b4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 27 Feb 2020 22:57:29 +0100 Subject: [PATCH 056/327] Use plural for test files --- exercises/concept/dates/{DatesTest.cs => DatesTests.cs} | 4 ++-- .../{EnumsAdvancedTest.cs => EnumsAdvancedTests.cs} | 2 +- exercises/concept/enums/{EnumsTest.cs => EnumsTests.cs} | 2 +- ...mbersFloatingPointTest.cs => NumbersFloatingPointTests.cs} | 2 +- exercises/concept/numbers/{NumbersTest.cs => NumbersTests.cs} | 2 +- exercises/concept/strings/{StringsTest.cs => StringsTests.cs} | 2 +- reference/examples/new-concept-exercise-arrays.md | 4 ++-- reference/implementing-a-concept-exercise.md | 4 ++-- 8 files changed, 11 insertions(+), 11 deletions(-) rename exercises/concept/dates/{DatesTest.cs => DatesTests.cs} (99%) rename exercises/concept/enums-advanced/{EnumsAdvancedTest.cs => EnumsAdvancedTests.cs} (99%) rename exercises/concept/enums/{EnumsTest.cs => EnumsTests.cs} (97%) rename exercises/concept/numbers-floating-point/{NumbersFloatingPointTest.cs => NumbersFloatingPointTests.cs} (99%) rename exercises/concept/numbers/{NumbersTest.cs => NumbersTests.cs} (97%) rename exercises/concept/strings/{StringsTest.cs => StringsTests.cs} (98%) diff --git a/exercises/concept/dates/DatesTest.cs b/exercises/concept/dates/DatesTests.cs similarity index 99% rename from exercises/concept/dates/DatesTest.cs rename to exercises/concept/dates/DatesTests.cs index 8ec50aea9f..3da83f2988 100644 --- a/exercises/concept/dates/DatesTest.cs +++ b/exercises/concept/dates/DatesTests.cs @@ -1,12 +1,12 @@ using Xunit; +using Xunit.Sdk; using System; using System.Globalization; using System.Reflection; using System.Threading; -using Xunit.Sdk; [UseCulture("en-US")] -public class AppointmentTest +public class AppointmentTests { [Fact] public void ScheduleDateUsingOnlyNumbers() => diff --git a/exercises/concept/enums-advanced/EnumsAdvancedTest.cs b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs similarity index 99% rename from exercises/concept/enums-advanced/EnumsAdvancedTest.cs rename to exercises/concept/enums-advanced/EnumsAdvancedTests.cs index 9e4a71e1a1..0f0d47a13a 100644 --- a/exercises/concept/enums-advanced/EnumsAdvancedTest.cs +++ b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs @@ -1,6 +1,6 @@ using Xunit; -public class PermissionsTest +public class PermissionsTests { [Fact] public void DefaultForGuest() => diff --git a/exercises/concept/enums/EnumsTest.cs b/exercises/concept/enums/EnumsTests.cs similarity index 97% rename from exercises/concept/enums/EnumsTest.cs rename to exercises/concept/enums/EnumsTests.cs index a36e121d29..bcaf8a5c71 100644 --- a/exercises/concept/enums/EnumsTest.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -1,6 +1,6 @@ using Xunit; -public class LogLineTest +public class LogLineTests { [Fact] public void ParseError() => diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs similarity index 99% rename from exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs rename to exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs index 9bd3ba1ce8..71a0da1abd 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPointTest.cs +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs @@ -1,6 +1,6 @@ using Xunit; -public class SavingsAccountTest +public class SavingsAccountTests { [Fact] public void MinimalFirstAnnualPercentageYield() => diff --git a/exercises/concept/numbers/NumbersTest.cs b/exercises/concept/numbers/NumbersTests.cs similarity index 97% rename from exercises/concept/numbers/NumbersTest.cs rename to exercises/concept/numbers/NumbersTests.cs index 2384932e65..bd1bf8987f 100644 --- a/exercises/concept/numbers/NumbersTest.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -1,6 +1,6 @@ using Xunit; -public class AssemblyLineTest +public class AssemblyLineTests { [Fact] public void ProductionRatePerHourForSpeedZero() => diff --git a/exercises/concept/strings/StringsTest.cs b/exercises/concept/strings/StringsTests.cs similarity index 98% rename from exercises/concept/strings/StringsTest.cs rename to exercises/concept/strings/StringsTests.cs index 4203add97e..f654f0c284 100644 --- a/exercises/concept/strings/StringsTest.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -1,6 +1,6 @@ using Xunit; -public class LogLineTest +public class LogLineTests { [Fact] public void ErrorMessage() => diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index e86138d3f9..df8c219033 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -92,7 +92,7 @@ languages | └── Example.cs ├── Arrays.csproj ├── Arrays.cs - └── ArraysTest.cs + └── ArraysTests.cs ## Step 1: add .docs/introduction.md @@ -143,7 +143,7 @@ An entry should be added to the track's `config.json` file for the new concept e These files are specific to the C# track: - `Arrays.csproj`: the C# project file. -- `ArraysTest.cs`: the test suite. +- `ArraysTests.cs`: the test suite. - `Arrays.cs`. the stub implementation file, which is the starting point for students to work on the exercise. - `.meta/Example.cs`: an example implementation that passes all the tests. diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 0cdbd0a57d..2ca3d6c82e 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -26,7 +26,7 @@ languages | └── Example.cs ├── <NAME>.cs ├── <NAME>.csproj - └── <NAME>Test.cs + └── <NAME>Tests.cs ## Step 1: adding track-specific files @@ -35,7 +35,7 @@ These files are specific to the C# track: - `.cs`. the stub implementation file, which is the starting point for students to work on the exercise. - `.csproj`: the C# project file. -- `Test.cs`: the test suite. +- `Tests.cs`: the test suite. - `.meta/Example.cs`: an example implementation that passes all the tests. ## Step 2: adding common files From bbad4e46d77b41ffd4a5cb97ffafef1d53a57e16 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 3 Mar 2020 23:19:17 +0100 Subject: [PATCH 057/327] Update after.md document for enums-advanced exercise --- exercises/concept/enums-advanced/.docs/after.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/enums-advanced/.docs/after.md index a1251c17ad..fc6aa85a20 100644 --- a/exercises/concept/enums-advanced/.docs/after.md +++ b/exercises/concept/enums-advanced/.docs/after.md @@ -1,6 +1,17 @@ -To allow an enum value to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By assigning the values of the enum such that each values has exactly one bit set to `1`, bitwise operators can be used to set or unset flags. +To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By assigning the values of the enum members such that each value has exactly one bit set to `1`, bitwise operators can be used to set or unset flags. + +Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. + +Besides using regular integers to set the flag enum members' values, one can also use [binary literals or the bitwise shift operator][binary-literals]. + +Note that an enum member's value can refer to other enum members values. The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. [docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ +[or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- +[and-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator- +[bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- +[binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals +[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 From 95fca88e81f0eee71fb5d3919bc2ae9f9546975f Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 3 Mar 2020 23:23:07 +0100 Subject: [PATCH 058/327] Update after.md document for numbers-floating-point exercise * Update after.md document for numbers-floating-point exercise * Update after.md --- exercises/concept/numbers-floating-point/.docs/after.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md index 1de731ae8e..205a99c701 100644 --- a/exercises/concept/numbers-floating-point/.docs/after.md +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -1,4 +1,4 @@ -There are three floating-point types in C#: `float`, `double` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. +There are three floating-point types in C#: `float`, `double` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is declared as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`. Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. From e1cd11d3a4895b1160a20ce09f101f78f903887c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 3 Mar 2020 23:24:15 +0100 Subject: [PATCH 059/327] Update after.md document for enums exercise * Update after.md document for enums exercise * Update languages/exercises/concept/enums/.docs/after.md Co-Authored-By: Jeremy Walker Co-authored-by: Jeremy Walker --- exercises/concept/enums/.docs/after.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md index d06b4a09b0..0457e964ed 100644 --- a/exercises/concept/enums/.docs/after.md +++ b/exercises/concept/enums/.docs/after.md @@ -1,4 +1,6 @@ -Whenever you have a fixed set of constant values, an `enum` can be used. Using an enum gives one a type-safe way of interacting with constant values. +You can use an enum whenever you have a fixed set of constant values. Using an enum gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`). + +Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`. Another benefit of enums are that they are very declarative. Compare the following two pieces of code: From 313f4d3eaa2493fc7a2bd9357364afd7f5e67d96 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 3 Mar 2020 23:25:32 +0100 Subject: [PATCH 060/327] Update after document for dates --- exercises/concept/dates/.docs/after.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/exercises/concept/dates/.docs/after.md b/exercises/concept/dates/.docs/after.md index d7e8d50a2c..aee6bac0de 100644 --- a/exercises/concept/dates/.docs/after.md +++ b/exercises/concept/dates/.docs/after.md @@ -1,3 +1,12 @@ -In C# dates are represented as `DateTime` instances, which contains both date _and_ time information. Dates can be compared using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the static `DateTime.Now` property. +A `DateTime` in C# is an immutable object that contains both date _and_ time information. The date and time information can be accessed through its built-in [properties][properties]. -An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s (either as input or output) will be dependent on the current culture. +Manipulating a `DateTime` can be done by calling one of its [methods][methods]. As `DateTime` values can never change after having been defined, all methods that appear to modify a `DateTime` will actually return a new `DateTime`. + +Comparing `DateTime` instances can be done using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the `DateTime.Now` property. + +An important aspect of dates in F# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s will be dependent on the current culture. This includes the [`DateTime.Parse()` method][parse] that parses a `string` to a `DateTime`, as well as the `DateTime` class' [`ToString()` method][to-string] that converts a `DateTime` to a `string`. + +[parse]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netcore-3.1#System_DateTime_Parse_System_String_ +[operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#operators +[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#properties +[to-string]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=netcore-3.1 From 82f685a5c11f16f3786e41737c7a22f1a4e48ef3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 12 Mar 2020 12:09:15 +0100 Subject: [PATCH 061/327] Explicitly mention method to implement in instructions --- exercises/concept/dates/.docs/instructions.md | 8 ++++---- .../concept/enums-advanced/.docs/instructions.md | 8 ++++---- exercises/concept/enums/.docs/instructions.md | 4 ++-- .../numbers-floating-point/.docs/instructions.md | 12 ++++++------ exercises/concept/numbers/.docs/instructions.md | 4 ++-- exercises/concept/strings/.docs/instructions.md | 14 +++++++------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md index 3e17d114e2..bb9aaec0fa 100644 --- a/exercises/concept/dates/.docs/instructions.md +++ b/exercises/concept/dates/.docs/instructions.md @@ -11,7 +11,7 @@ The tests will automatically set the culture to `en-US` - you don't have to set ### 1. Parse appointment date -Implement a method that can parse a textual representation of an appointment date into the corresponding `DateTime` format: +Implement the `Appointment.Schedule` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: ```csharp Appointment.Schedule("7/25/2019 13:45:00") @@ -20,7 +20,7 @@ Appointment.Schedule("7/25/2019 13:45:00") ### 2. Check if an appointment has already passed -Implement a method that takes an appointment date and checks if the appointment was somewhere in the past: +Implement the `Appointment.HasPassed` method that takes an appointment date and checks if the appointment was somewhere in the past: ```csharp Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) @@ -29,7 +29,7 @@ Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) ### 3. Check if appointment is in the afternoon -Implement a method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): +Implement the `Appointment.IsAfternoonAppointment` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): ```csharp Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) @@ -38,7 +38,7 @@ Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) ### 4. Describe the time and date of the appointment -Implement a method that takes an appointment date and returns a description of that date and time: +Implement the `Appointment.Description` method that takes an appointment date and returns a description of that date and time: ```csharp Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) diff --git a/exercises/concept/enums-advanced/.docs/instructions.md b/exercises/concept/enums-advanced/.docs/instructions.md index 35fcf8ae89..01b6ac72c7 100644 --- a/exercises/concept/enums-advanced/.docs/instructions.md +++ b/exercises/concept/enums-advanced/.docs/instructions.md @@ -18,7 +18,7 @@ You have four tasks. First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions. -Then implement a method to return the default permissions for a specific account type: +Then implement the `Permissions.Default` method to return the default permissions for a specific account type: ```csharp Permissions.Default(AccountType.Guest) @@ -27,7 +27,7 @@ Permissions.Default(AccountType.Guest) ### 2. Grant a permission -Implement a method that grants (adds) a permission: +Implement the `Permissions.Grant` method that grants (adds) a permission: ```csharp Permissions.Grant(current: Permission.None, grant: Permission.Read) @@ -36,7 +36,7 @@ Permissions.Grant(current: Permission.None, grant: Permission.Read) ### 3. Revoke a permission -Implement a method that revokes (removes) a permission: +Implement the `Permissions.Revoke` method that revokes (removes) a permission: ```csharp Permissions.Revoke(current: Permission.Read, grant: Permission.Read) @@ -45,7 +45,7 @@ Permissions.Revoke(current: Permission.Read, grant: Permission.Read) ### 4. Check for a permission -Implement a method that takes the current account's permissions and checks if the account is authorized for a given permission: +Implement the `Permissions.Check` method that takes the current account's permissions and checks if the account is authorized for a given permission: ```csharp Permissions.Check(current: Permission.Write, check: Permission.Read) diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index 1bdb2880b6..c6d3cfae45 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -18,7 +18,7 @@ Define a `LogLevel` enum that has three elements: - `Warning` - `Error` -Next, implement a method to parse the log level of a log line: +Next, implement the `LogLine.ParseLogLevel` method to parse the log level of a log line: ```csharp LogLine.ParseLogLevel("[INFO]: File deleted") @@ -45,7 +45,7 @@ The encoded log level is simple mapping of a log level to a number: - `Warning` -> `2` - `Error` -> `4` -Implement a method that can output the shortened log line format: +Implement the `LogLine.OutputForShortLog` method that can output the shortened log line format: ```csharp LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/numbers-floating-point/.docs/instructions.md index e24d8abfab..c22cc62572 100644 --- a/exercises/concept/numbers-floating-point/.docs/instructions.md +++ b/exercises/concept/numbers-floating-point/.docs/instructions.md @@ -9,10 +9,10 @@ You have three tasks, each of which will deal with balances and their APYs. ### 1. Calculate the annual percentage yield -Implement a method to calculate the APY based on the specified balance: +Implement the `SavingsAccount.AnnualPercentageYield` method to calculate the APY based on the specified balance: ```csharp -FloatingPointNumbers.AnnualPercentageYield(balance: 200.75m) +SavingsAccount.AnnualPercentageYield(balance: 200.75m) // 0.5f ``` @@ -20,10 +20,10 @@ Note that the value returned is a `float`. ### 2. Calculate the annual balance update -Implement a method to calculate the annual balance update, taking into account the APY: +Implement the `SavingsAccount.AnnualBalanceUpdate` method to calculate the annual balance update, taking into account the APY: ```csharp -FloatingPointNumbers.AnnualBalanceUpdate(balance: 200.75m) +SavingsAccount.AnnualBalanceUpdate(balance: 200.75m) // 201.75375m ``` @@ -31,10 +31,10 @@ Note that the value returned is a `decimal`. ### 3. Calculate the years before reaching the desired balance -Implement a method to calculate the minimum number of years required to reach the desired balance: +Implement the `SavingsAccount.YearsBeforeDesiredBalance` method to calculate the minimum number of years required to reach the desired balance: ```csharp -FloatingPointNumbers.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88m) +SavingsAccount.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88m) // 14 ``` diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index f2a0eb1991..6ce25e4b30 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -10,7 +10,7 @@ You have two tasks. ### 1. Calculate the production rate per hour -Implement a method to calculate the assembly line's production rate per hour, taking into account its success rate: +Implement the `AssemblyLine.ProductionRatePerHour` method to calculate the assembly line's production rate per hour, taking into account its success rate: ```csharp AssemblyLine.ProductionRatePerHour(speed: 6) @@ -21,7 +21,7 @@ Note that the value returned is a `double`. ### 2. Calculate the number of working items produced per minute -Implement a method to calculate how many working cars are produced per minute: +Implement the `AssemblyLine.WorkingItemsPerMinute` method to calculate how many working cars are produced per minute: ```csharp AssemblyLine.WorkingItemsPerMinute(speed: 6) diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index 5d7c73c672..d703594eac 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -12,34 +12,34 @@ You have three tasks, each of which will take a log line and ask you to do somet ### 1. Get message from a log line -Implement a method to return a log line's message: +Implement the `LogLine.Message` method to return a log line's message: ```csharp -Strings.Message("[ERROR]: Invalid operation") +LogLine.Message("[ERROR]: Invalid operation") // Returns: "Invalid operation" ``` Any leading or trailing white space should be removed: ```csharp -Strings.Message("[WARNING]: Disk almost full\r\n") +LogLine.Message("[WARNING]: Disk almost full\r\n") // Returns: "Disk almost full" ``` ### 2. Get log level from a log line -Implement a method to return a log line's log level, which should be returned in lowercase: +Implement the `LogLine.LogLevel` method to return a log line's log level, which should be returned in lowercase: ```csharp -Strings.LogLevel("[ERROR]: Invalid operation") +LogLine.LogLevel("[ERROR]: Invalid operation") // Returns: "error" ``` ### 3. Reformat a log line -Implement a method that reformats the log line, putting the message first and the log level after it in parentheses: +Implement the `LogLine.Reformat` method that reformats the log line, putting the message first and the log level after it in parentheses: ```csharp -Strings.Reformat("[INFO]: Operation completed") +LogLine.Reformat("[INFO]: Operation completed") // Returns: "Operation completed (info)" ``` From 3c8da14bbd52319eecac5a701f1bf33f2d5cf88a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 13 Mar 2020 12:35:19 +0100 Subject: [PATCH 062/327] Simplify display of returned value --- exercises/concept/dates/.docs/instructions.md | 8 ++++---- exercises/concept/enums-advanced/.docs/instructions.md | 8 ++++---- exercises/concept/enums/.docs/instructions.md | 6 +++--- exercises/concept/numbers/.docs/instructions.md | 4 ++-- exercises/concept/strings/.docs/instructions.md | 8 ++++---- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md index bb9aaec0fa..1c4e37384c 100644 --- a/exercises/concept/dates/.docs/instructions.md +++ b/exercises/concept/dates/.docs/instructions.md @@ -15,7 +15,7 @@ Implement the `Appointment.Schedule` method to parse a textual representation of ```csharp Appointment.Schedule("7/25/2019 13:45:00") -// Returns: new DateTime(2019, 7, 25, 13, 45, 0) +// => new DateTime(2019, 7, 25, 13, 45, 0) ``` ### 2. Check if an appointment has already passed @@ -24,7 +24,7 @@ Implement the `Appointment.HasPassed` method that takes an appointment date and ```csharp Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) -// Returns: true +// => true ``` ### 3. Check if appointment is in the afternoon @@ -33,7 +33,7 @@ Implement the `Appointment.IsAfternoonAppointment` method that takes an appointm ```csharp Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) -// Returns: true +// => true ``` ### 4. Describe the time and date of the appointment @@ -42,5 +42,5 @@ Implement the `Appointment.Description` method that takes an appointment date an ```csharp Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) -// Returns: "You have an appointment on Friday 29 March 2019 at 15:00." +// => "You have an appointment on Friday 29 March 2019 at 15:00." ``` diff --git a/exercises/concept/enums-advanced/.docs/instructions.md b/exercises/concept/enums-advanced/.docs/instructions.md index 01b6ac72c7..ad31bcdfd0 100644 --- a/exercises/concept/enums-advanced/.docs/instructions.md +++ b/exercises/concept/enums-advanced/.docs/instructions.md @@ -22,7 +22,7 @@ Then implement the `Permissions.Default` method to return the default permission ```csharp Permissions.Default(AccountType.Guest) -// Returns: Permission.Read +// => Permission.Read ``` ### 2. Grant a permission @@ -31,7 +31,7 @@ Implement the `Permissions.Grant` method that grants (adds) a permission: ```csharp Permissions.Grant(current: Permission.None, grant: Permission.Read) -// Returns: Permission.Read +// => Permission.Read ``` ### 3. Revoke a permission @@ -40,7 +40,7 @@ Implement the `Permissions.Revoke` method that revokes (removes) a permission: ```csharp Permissions.Revoke(current: Permission.Read, grant: Permission.Read) -// Returns: Permission.None +// => Permission.None ``` ### 4. Check for a permission @@ -49,5 +49,5 @@ Implement the `Permissions.Check` method that takes the current account's permis ```csharp Permissions.Check(current: Permission.Write, check: Permission.Read) -// Returns: false +// => false ``` diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index c6d3cfae45..f7c8ad1fba 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -22,7 +22,7 @@ Next, implement the `LogLine.ParseLogLevel` method to parse the log level of a l ```csharp LogLine.ParseLogLevel("[INFO]: File deleted") -// Returns: LogLevel.Info +// => LogLevel.Info ``` ### 2. Support unknown log level @@ -31,7 +31,7 @@ Unfortunately, occasionally some log lines have an unknown log level. To gracefu ```csharp LogLine.ParseLogLevel("[FATAL]: Invalid operation") -// Returns: LogLevel.Unknown +// => LogLevel.Unknown ``` ### 3. Convert log line to short format @@ -49,5 +49,5 @@ Implement the `LogLine.OutputForShortLog` method that can output the shortened l ```csharp LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") -// Returns: "4:Stack overflow" +// => "4:Stack overflow" ``` diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index 6ce25e4b30..26e28a1bc6 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -14,7 +14,7 @@ Implement the `AssemblyLine.ProductionRatePerHour` method to calculate the assem ```csharp AssemblyLine.ProductionRatePerHour(speed: 6) -// Returns: 1193.4 +// => 1193.4 ``` Note that the value returned is a `double`. @@ -25,7 +25,7 @@ Implement the `AssemblyLine.WorkingItemsPerMinute` method to calculate how many ```csharp AssemblyLine.WorkingItemsPerMinute(speed: 6) -// Returns: 19 +// => 19 ``` Note that the value returned is an `int`. diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index d703594eac..507ee8e209 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -16,14 +16,14 @@ Implement the `LogLine.Message` method to return a log line's message: ```csharp LogLine.Message("[ERROR]: Invalid operation") -// Returns: "Invalid operation" +// => "Invalid operation" ``` Any leading or trailing white space should be removed: ```csharp LogLine.Message("[WARNING]: Disk almost full\r\n") -// Returns: "Disk almost full" +// => "Disk almost full" ``` ### 2. Get log level from a log line @@ -32,7 +32,7 @@ Implement the `LogLine.LogLevel` method to return a log line's log level, which ```csharp LogLine.LogLevel("[ERROR]: Invalid operation") -// Returns: "error" +// => "error" ``` ### 3. Reformat a log line @@ -41,5 +41,5 @@ Implement the `LogLine.Reformat` method that reformats the log line, putting the ```csharp LogLine.Reformat("[INFO]: Operation completed") -// Returns: "Operation completed (info)" +// => "Operation completed (info)" ``` From dac0cb1bdd5bcdfe9de7442654a6285ef33e66ee Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 13 Mar 2020 12:35:52 +0100 Subject: [PATCH 063/327] Update introduction of Dates exercise --- exercises/concept/dates/.docs/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/dates/.docs/introduction.md b/exercises/concept/dates/.docs/introduction.md index 63a3fed691..7ba7a7786f 100644 --- a/exercises/concept/dates/.docs/introduction.md +++ b/exercises/concept/dates/.docs/introduction.md @@ -1,4 +1,4 @@ -The C# `DateTime` type is a type that contains both date and time information. +A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`. The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`. From 42a4c4d41d3b1defbb87ac49baa6516c9d6a2fa2 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sun, 15 Mar 2020 16:41:40 +0100 Subject: [PATCH 064/327] Mention if/else statement in introduction of numbers exercise --- exercises/concept/numbers/.docs/introduction.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index dc3008c511..cff1096137 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -5,11 +5,11 @@ There are two different types of numbers in C#: The two most common numeric types in C# are `int` and `double`. An `int` is a 32-bit integer and a `double` is a 64-bit floating-point number. -## Converting between number types - C# has two types of numeric conversions: 1. Implicit conversions: no data will be lost and no additional syntax is required. 2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. + +In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement. From 1765bfdb7e6be3fca686eeb06270d6f7202f6b98 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 18 Mar 2020 11:45:17 +0100 Subject: [PATCH 065/327] Update phrasing of NumbersFloatingPoint exercise --- .../numbers-floating-point/.docs/after.md | 2 +- .../numbers-floating-point/.docs/hints.md | 2 +- .../.docs/instructions.md | 20 ++++--- .../numbers-floating-point/.meta/Example.cs | 4 +- .../numbers-floating-point/.meta/design.md | 4 +- .../NumbersFloatingPoint.cs | 4 +- .../NumbersFloatingPointTests.cs | 52 +++++++++---------- 7 files changed, 43 insertions(+), 45 deletions(-) diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/numbers-floating-point/.docs/after.md index 205a99c701..b19ce1b9ce 100644 --- a/exercises/concept/numbers-floating-point/.docs/after.md +++ b/exercises/concept/numbers-floating-point/.docs/after.md @@ -1,4 +1,4 @@ -There are three floating-point types in C#: `float`, `double` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is declared as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`. +There are three floating-point types in C#: `double`, `float` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is written as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`. Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/numbers-floating-point/.docs/hints.md index 2ef80f29a2..f20ee10423 100644 --- a/exercises/concept/numbers-floating-point/.docs/hints.md +++ b/exercises/concept/numbers-floating-point/.docs/hints.md @@ -2,7 +2,7 @@ - [Floating-point numeric types introduction][docs.microsoft.com-floating_point_numeric_types]. -### 1. Calculate the annual percentage yield +### 1. Calculate the interest rate - By default, any floating-point number defined in C# code is treated as a `double`. To use a different floating-point type (like `float` or `decimal`), one must add the appropriate [suffix][docs.microsoft.com-real_literals] to the number. diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/numbers-floating-point/.docs/instructions.md index c22cc62572..09f7c3aea7 100644 --- a/exercises/concept/numbers-floating-point/.docs/instructions.md +++ b/exercises/concept/numbers-floating-point/.docs/instructions.md @@ -1,18 +1,18 @@ -In this exercise you'll be working with savings accounts. Each year, the balance of each savings account is updated based on the [annual percentage yield][wikipedia-annual_percentage_yield] (APY). The APY value depends on the amount of money in the account (its balance): +In this exercise you'll be working with savings accounts. Each year, the balance of your savings account is updated based on its interest rate. The interest rate your bank gives you depends on the amount of money in your account (its balance): - -3.213% for a negative balance. -- 0.5% for a positive balance less than `1000`. -- 1.621% for a positive balance greater or equal than `1000` and less than `5000`. -- 2.475% for a positive balance greater or equal than `5000`. +- 0.5% for a positive balance less than `1000` dollars. +- 1.621% for a positive balance greater or equal than `1000` dollars and less than `5000` dollars. +- 2.475% for a positive balance greater or equal than `5000` dollars. -You have three tasks, each of which will deal with balances and their APYs. +You have three tasks, each of which will deal your balance and its interest rate. -### 1. Calculate the annual percentage yield +### 1. Calculate the interest rate -Implement the `SavingsAccount.AnnualPercentageYield` method to calculate the APY based on the specified balance: +Implement the `SavingsAccount.InterestRate` method to calculate the interest rate based on the specified balance: ```csharp -SavingsAccount.AnnualPercentageYield(balance: 200.75m) +SavingsAccount.InterestRate(balance: 200.75m) // 0.5f ``` @@ -20,7 +20,7 @@ Note that the value returned is a `float`. ### 2. Calculate the annual balance update -Implement the `SavingsAccount.AnnualBalanceUpdate` method to calculate the annual balance update, taking into account the APY: +Implement the `SavingsAccount.AnnualBalanceUpdate` method to calculate the annual balance update, taking into account the interest rate: ```csharp SavingsAccount.AnnualBalanceUpdate(balance: 200.75m) @@ -39,5 +39,3 @@ SavingsAccount.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88 ``` Note that the value returned is an `int`. - -[wikipedia-annual_percentage_yield]: https://en.wikipedia.org/wiki/Annual_percentage_yield diff --git a/exercises/concept/numbers-floating-point/.meta/Example.cs b/exercises/concept/numbers-floating-point/.meta/Example.cs index 9f4ca05627..49acf77217 100644 --- a/exercises/concept/numbers-floating-point/.meta/Example.cs +++ b/exercises/concept/numbers-floating-point/.meta/Example.cs @@ -2,7 +2,7 @@ public static class SavingsAccount { - public static float AnnualPercentageYield(decimal balance) + public static float InterestRate(decimal balance) { if (balance < 0.0m) return -3.213f; @@ -18,7 +18,7 @@ public static float AnnualPercentageYield(decimal balance) private static decimal AnnualYield(decimal balance) { - var multiplier = (decimal)AnnualPercentageYield(balance) / 100; + var multiplier = (decimal)InterestRate(balance) / 100; return Math.Abs(balance) * multiplier; } diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md index 6a6b999cbb..7760150eda 100644 --- a/exercises/concept/numbers-floating-point/.meta/design.md +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -7,7 +7,7 @@ The goal of this exercise is to teach the student how the Concept of floating-po ## Learning objectives - Know of the existence of the three floating point types: `double`, `float` and `decimal`. -- Know when to use which type. +- Know when to use which floating point type. - Know how to write a `while` loop. ## Out of scope @@ -20,7 +20,7 @@ The goal of this exercise is to teach the student how the Concept of floating-po The Concepts this exercise unlocks are: -- `numbers-floating-point`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which type. +- `numbers-floating-point`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. - `loops-while`: know how to write a `while` loop. ## Prequisites diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs index 081c2e065d..3b54ef28c3 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs @@ -2,9 +2,9 @@ public static class SavingsAccount { - public static float AnnualPercentageYield(decimal balance) + public static float InterestRate(decimal balance) { - throw new NotImplementedException("Please implement the SavingsAccount.AnnualPercentageYield method"); + throw new NotImplementedException("Please implement the SavingsAccount.InterestRate method"); } public static decimal AnnualBalanceUpdate(decimal balance) diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs index 71a0da1abd..f1eb36fa96 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs @@ -3,56 +3,56 @@ public class SavingsAccountTests { [Fact] - public void MinimalFirstAnnualPercentageYield() => - Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(0m)); + public void MinimalFirstInterestRate() => + Assert.Equal(0.5f, SavingsAccount.InterestRate(0m)); [Fact] - public void TinyFirstAnnualPercentageYield() => - Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(0.000001m)); + public void TinyFirstInterestRate() => + Assert.Equal(0.5f, SavingsAccount.InterestRate(0.000001m)); [Fact] - public void MaximumFirstAnnualPercentageYield() => - Assert.Equal(0.5f, SavingsAccount.AnnualPercentageYield(999.9999m)); + public void MaximumFirstInterestRate() => + Assert.Equal(0.5f, SavingsAccount.InterestRate(999.9999m)); [Fact] - public void MinimalSecondAnnualPercentageYield() => - Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(1_000.0m)); + public void MinimalSecondInterestRate() => + Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0m)); [Fact] - public void TinySecondAnnualPercentageYield() => - Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(1_000.0001m)); + public void TinySecondInterestRate() => + Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0001m)); [Fact] - public void MaximumSecondAnnualPercentageYield() => - Assert.Equal(1.621f, SavingsAccount.AnnualPercentageYield(4_999.9990m)); + public void MaximumSecondInterestRate() => + Assert.Equal(1.621f, SavingsAccount.InterestRate(4_999.9990m)); [Fact] - public void MinimalThirdAnnualPercentageYield() => - Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_000.0000m)); + public void MinimalThirdInterestRate() => + Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0000m)); [Fact] - public void TinyThirdAnnualPercentageYield() => - Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_000.0001m)); + public void TinyThirdInterestRate() => + Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0001m)); [Fact] - public void LargeThirdAnnualPercentageYield() => - Assert.Equal(2.475f, SavingsAccount.AnnualPercentageYield(5_639_998.742909m)); + public void LargeThirdInterestRate() => + Assert.Equal(2.475f, SavingsAccount.InterestRate(5_639_998.742909m)); [Fact] - public void MinimalNegativeAnnualPercentageYield() => - Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-0.000001m)); + public void MinimalNegativeInterestRate() => + Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.000001m)); [Fact] - public void SmallNegativeAnnualPercentageYield() => - Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-0.123m)); + public void SmallNegativeInterestRate() => + Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.123m)); [Fact] - public void RegularNegativeAnnualPercentageYield() => - Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-300.0m)); + public void RegularNegativeInterestRate() => + Assert.Equal(-3.213f, SavingsAccount.InterestRate(-300.0m)); [Fact] - public void LargeNegativeAnnualPercentageYield() => - Assert.Equal(-3.213f, SavingsAccount.AnnualPercentageYield(-152964.231m)); + public void LargeNegativeInterestRate() => + Assert.Equal(-3.213f, SavingsAccount.InterestRate(-152964.231m)); [Fact] public void AnnualBalanceUpdateForEmptyStartBalance() => From d8261a190af4325d25577106ce6abc4e286281a3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 18 Mar 2020 12:15:15 +0100 Subject: [PATCH 066/327] Add operators information to Numbers exercise --- exercises/concept/numbers/.docs/after.md | 8 ++++++-- exercises/concept/numbers/.docs/introduction.md | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md index 2d9ed01ae0..7999c4ddbe 100644 --- a/exercises/concept/numbers/.docs/after.md +++ b/exercises/concept/numbers/.docs/after.md @@ -1,8 +1,8 @@ One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). -The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). +The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). -Numbers can be compared using the default comparison operators (`<`, `>`, `==`, etc.). These operators can be used in `if` statements to conditionally execute code. +Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.). The result of a comparison can be used in `if` statements to conditionally execute code. When converting between numeric types, there are two types of numeric conversions: @@ -10,3 +10,7 @@ When converting between numeric types, there are two types of numeric conversion 2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. + +[arithmetic-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators +[equality-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators +[comparison-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index cff1096137..b51e9f7f4a 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -5,6 +5,8 @@ There are two different types of numbers in C#: The two most common numeric types in C# are `int` and `double`. An `int` is a 32-bit integer and a `double` is a 64-bit floating-point number. +Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators. + C# has two types of numeric conversions: 1. Implicit conversions: no data will be lost and no additional syntax is required. From 9a958e5799c9aa79faf35068a3374e647cb31480 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 26 Mar 2020 15:40:21 +0100 Subject: [PATCH 067/327] Clarify syntax in introduction document [Docs] Clarify syntax in introduction document Co-Authored-By: Jeremy Walker --- reference/examples/new-concept-exercise-arrays.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index df8c219033..eb181c7fbc 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -97,7 +97,9 @@ languages ## Step 1: add .docs/introduction.md -This file contains an introduction to the concept. It should be explicit about what the student should learn from the exercise, and provide a short, concise introduction to the concept(s). The aim is to give the student just enough context to figure things out themselves and solve the exercise, as research has shown that self-discovery is the most effective learning experience. Mentioning technical terms that the student can Google if they so want, is preferable over including any code samples or an extensive description. For example we might describe a string as a "Sequence of Unicode characters" or a "series of bytes" or "an object". Unless the student needs to understand the details of what those mean to be able to solve the exercise we should not give more info in this introduction - instead allowing the student to Google, ignore, or map their existing knowledge. +This file contains an introduction to the concept. It should make the exercise's learning goals explicit and provide a short introduction with enough detail for the student to complete the exercise. The aim is to give the student just enough context to figure out the solution themselves, as research has shown that self-discovery is the most effective learning experience. Using the proper technical terms in the descriptions will be helpful if the student wants to search for more information. If the exercise introduces new syntax, an example of the syntax should always be included; students should not need to search the web for examples of syntax. + +As an example, the introduction to a "strings" exercise might describe a string as just a "Sequence of Unicode characters" or a "series of bytes". Unless the student needs to understand more nuanced details in order to solve the exercise, this type of brief explanation (along with an example of its syntax) should be sufficient information for the student to solve the exercise. ## Step 2: add .docs/instructions.md From 28c0c2948af91cf9fc6e7d613534ed53ce2363a6 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sun, 29 Mar 2020 19:12:43 +0200 Subject: [PATCH 068/327] Simplify new exercise issue * Simplify new exercise issue * Update languages/reference/examples/new-concept-exercise-arrays.md Co-Authored-By: wolf99 Co-authored-by: Rob Keim Co-authored-by: wolf99 --- .../examples/new-concept-exercise-arrays.md | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index eb181c7fbc..7f2def1fe4 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -1,12 +1,8 @@ -# [C#] Add new Concept Exercise - arrays - -This issue describes a new `arrays` exercise that should be added to the [v3 C# track][csharp-docs]. +This issue describes how to implement the `array` concept exercise for the C# track. ## Goal -The goal of this exercise is to teach the student how the concept of [collections][docs-v3-types-collection] is implemented in [C#][docs.microsoft.com-collections]. We'll teach the student about collections by having the student work with one specific type of collection, namely the [array][docs-v3-types-array]. The students will learn to define arrays, iterate over array items, access items by index, and more. - -Of the many available C# collection types, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons: +The goal of this exercise is to teach the student the basics of the Concept of Arrays in [C#][arrays]. We'll use the array type to teach the student about some collection basics. The `array` collection type was chosen as the first collection type for the following reasons: - Arrays don't require the student to know about generics. - Arrays are a common data type in many language. @@ -38,8 +34,6 @@ This Concepts Exercise's Concepts are: ## Prequisites -As an array is a collection type, it holds zero or more instances of another type. That means it _has_ to depend on one or more other types. In this exercise, we'll use the `int` data type for that, which is both interesting enough and easy to work with. The `int` data type is introduced in the `numbers-basic` concept. - This Concept Exercise's prerequisites Concepts are: - `numbers-basic`: `int` values will be stored in the array and returned as output. @@ -48,26 +42,29 @@ This Concept Exercise's prerequisites Concepts are: ### Hints -- [Arrays][docs.microsoft.com-arrays] -- [Single-dimensional arrays][docs.microsoft.com-single-dimensional-arrays] -- [Usings foreach with arrays][docs.microsoft.com-foreach-with-arrays] +- [Arrays][arrays]: basic information on strings. +- [Single-dimensional arrays][single-dimensional-arrays]: how to define a single-dimensional array. +- [Usings foreach with arrays][foreach]: how to iterate over an array using a `foreach` loop. ### After -- [Collections][docs.microsoft.com-collections] -- [Implicitly typed arrays][docs.microsoft.com-implicitly-typed-arrays] +- [Arrays][arrays]: basic information on strings. +- [Single-dimensional arrays][single-dimensional-arrays]: how to define a single-dimensional array. +- [Usings foreach with arrays][foreach]: how to iterate over an array using a `foreach` loop. +- [Implicitly typed arrays][implicitly-typed-arrays]: how to define implicitly-typed arrays. +- [Collections][collections]: how collections work. As this is an introductory exercise, we should take care not to link to very advanced resources, to prevent overwhelming the student. ## Representer -This exercise does not require any specific representation logic to be added to the [representer][csharp-representer]. +This exercise does not require any specific representation logic to be added to the [representer][representer]. ## Analyzer -This exercise could benefit from having an [analyzer][csharp-analyzer] that can comment on: +This exercise could benefit from having an [analyzer][analyzer] that can comment on: -- Difference between `for` vs `foreach` loops. +- Suggest using `foreach` if a `for` loop is used. ## Implementing @@ -117,7 +114,7 @@ The hints should not spell out the solution, but instead point to a resource des Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. -The above four files are also all described in the [concept exercises document][docs-concept-exercises]. +The above four files are also all described in the [concept exercises document][concept-exercises]. ## Step 5: update languages/csharp/config.json @@ -149,50 +146,41 @@ These files are specific to the C# track: - `Arrays.cs`. the stub implementation file, which is the starting point for students to work on the exercise. - `.meta/Example.cs`: an example implementation that passes all the tests. -Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-floating-point-numbers] for an example on what these files should look like. +Check out [an existing exercise][exercise-example] to see what these files should look like. ## Step 7: update the general concept document -Add the exercise to the [concept's shared document's][referrence-array] `## Implementations` section ([example](https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations)). +Add the exercise to the [concept's shared document's][reference-array] `## Implementations` section ([example][reference-example]). ## Step 8: updating list of implemented exercises -- Add the exercise to the [list of implemented exercises][csharp-docs-concept-exercises]. +- Add the exercise to the [list of implemented exercises][implemented-exercises]. ## Step 9: add .meta/design.md: -This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][meta-design]). This information can be extracted from this GitHub issue. +This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][design-example]). This information can be extracted from this GitHub issue. ## Step 10: add .meta/config.json: -This file contains meta information on the exercise, which currently only includes the exercise's contributors ([example][meta-config.json]). +This file contains meta information on the exercise, which currently only includes the exercise's contributors ([example][config.json-example]). ### Inspiration -When implementing this exericse, it can be very useful to look at already implemented C# exercises like the [strings][csharp-docs-concept-exercises-strings], [dates][csharp-docs-concept-exercises-dates] or [floating-point numbers][csharp-docs-concept-exercises-floating-point-numbers] exercises. You can also check the [general array concept documentation][docs-v3-types-array] to see if any other languages have already implemented an arrays exercise. - -[docs.microsoft.com-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/ -[docs.microsoft.com-collections]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections -[docs.microsoft.com-foreach-with-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays -[docs.microsoft.com-single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays -[docs.microsoft.com-implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays -[docs-v3]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md#exercise-structure -[docs-v3-types-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md -[docs-v3-types-collection]: https://github.com/exercism/v3/blob/master/reference/types/collection.md -[csharp-docs]: https://github.com/exercism/v3/blob/master/languages/csharp/README.md -[csharp-docs-concept-exercises-strings]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/strings -[csharp-docs-concept-exercises-dates]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates -[csharp-docs-concept-exercises-floating-point-numbers]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point -[csharp-analyzer]: https://github.com/exercism/csharp-analyzer -[csharp-representer]: https://github.com/exercism/csharp-representer -[csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md -[csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md -[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/after.md -[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/hints.md -[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/introduction.md -[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/instructions.md -[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/design.md -[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.meta/config.json -[csharp-docs-concept-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md -[referrence-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md -[meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/enums-advanced/.meta/config.json +When implementing this exericse, it can be very useful to look at [already implemented C# exercises][implemented-exercises]. You can also check the [general array concept documentation][reference-array] to see if any other languages have already implemented an arrays exercise. + +[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/master/docs/maintainers/generic-how-to-implement-a-concept-exercise.md +[implemented-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md#implemented-exercises +[reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs +[reference-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md +[reference-example]: https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[design-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/design.md +[config.json-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/config.json +[concept-exercises]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md +[arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/ +[collections]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections +[foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays From ed2191ed98766adfd8ec0d75f2d855170add04b4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sun, 29 Mar 2020 20:12:11 +0200 Subject: [PATCH 069/327] Add hint to increment operator --- exercises/concept/numbers-floating-point/.docs/hints.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/numbers-floating-point/.docs/hints.md index f20ee10423..e4909a899e 100644 --- a/exercises/concept/numbers-floating-point/.docs/hints.md +++ b/exercises/concept/numbers-floating-point/.docs/hints.md @@ -13,8 +13,10 @@ ### 3. Calculate the years before reaching the desired balance - To calculate the years, one can keep looping until the desired balance is reached. C# has several [looping constructs][docs.microsoft.com-loops]. +- There is a special [operator][increment-operator] to increment values by 1. [docs-microsoft.com-system.math]: https://docs.microsoft.com/en-us/dotnet/api/system.math?view=netcore-3.0 [docs.microsoft.com-floating_point_numeric_types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types [docs.microsoft.com-real_literals]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#real-literals [docs.microsoft.com-loops]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/branches-and-loops-local#use-loops-to-repeat-operations +[increment-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#increment-operator- From 9a8008dda53a213d0d3a3f74ec38ce7ee7bd390e Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 31 Mar 2020 08:34:07 +0200 Subject: [PATCH 070/327] Add skip attribute --- exercises/concept/dates/DatesTests.cs | 46 +++++++++---------- .../enums-advanced/EnumsAdvancedTests.cs | 42 ++++++++--------- exercises/concept/enums/EnumsTests.cs | 14 +++--- .../NumbersFloatingPointTests.cs | 46 +++++++++---------- exercises/concept/numbers/NumbersTests.cs | 18 ++++---- exercises/concept/strings/StringsTests.cs | 20 ++++---- 6 files changed, 93 insertions(+), 93 deletions(-) diff --git a/exercises/concept/dates/DatesTests.cs b/exercises/concept/dates/DatesTests.cs index 3da83f2988..f98d78cb45 100644 --- a/exercises/concept/dates/DatesTests.cs +++ b/exercises/concept/dates/DatesTests.cs @@ -12,95 +12,95 @@ public class AppointmentTests public void ScheduleDateUsingOnlyNumbers() => Assert.Equal(new DateTime(2019, 07, 25, 13, 45, 0), Appointment.Schedule("7/25/2019 13:45:00")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ScheduleDateWithTextualMonth() => Assert.Equal(new DateTime(2019, 6, 3, 11, 30, 0), Appointment.Schedule("June 3, 2019 11:30:00")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ScheduleDateWithTextualMonthAndWeekday() => Assert.Equal(new DateTime(2019, 12, 5, 9, 0, 0), Appointment.Schedule("Thursday, December 5, 2019 09:00:00")); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentOneYearAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentMonthsAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMonths(-8))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentDaysAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddDays(-23))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentHoursAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddHours(-12))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentMinutesAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-55))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentOneMinuteAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-1))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentInOneMinute() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(1))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentInMinutes() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(5))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentInDays() => Assert.False(Appointment.HasPassed(DateTime.Now.AddDays(19))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentInMonths() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMonths(10))); - [Fact] + [Fact(Skip = "Remove to run test")] public void HasPassedWithAppointmentInYears() => Assert.False(Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForEarlyMorningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForLateMorningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForNoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForEarlyAfternoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForLateAfternoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForEarlyEveningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))); - [Fact] + [Fact(Skip = "Remove to run test")] public void IsAfternoonAppointmentForLateEveningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))); - [Fact] + [Fact(Skip = "Remove to run test")] public void DescriptionOnFridayAfternoon() => Assert.Equal("You have an appointment on 3/29/2019 3:00:00 PM.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); - [Fact] + [Fact(Skip = "Remove to run test")] public void DescriptionOnThursdayAfternoon() => Assert.Equal("You have an appointment on 7/25/2019 1:45:00 PM.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); - [Fact] + [Fact(Skip = "Remove to run test")] public void DescriptionOnWednesdayMorning() => Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); diff --git a/exercises/concept/enums-advanced/EnumsAdvancedTests.cs b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs index 0f0d47a13a..4210117966 100644 --- a/exercises/concept/enums-advanced/EnumsAdvancedTests.cs +++ b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs @@ -6,87 +6,87 @@ public class PermissionsTests public void DefaultForGuest() => Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest)); - [Fact] + [Fact(Skip = "Remove to run test")] public void DefaultForUser() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Default(AccountType.User)); - [Fact] + [Fact(Skip = "Remove to run test")] public void DefaultForModerator() => Assert.Equal(Permission.Read | Permission.Write | Permission.Delete, Permissions.Default(AccountType.Moderator)); - [Fact] + [Fact(Skip = "Remove to run test")] public void DefaultForUnknown() => Assert.Equal(Permission.None, Permissions.Default((AccountType)123)); - [Fact] + [Fact(Skip = "Remove to run test")] public void GrantReadToNone() => Assert.Equal(Permission.Read, Permissions.Grant(Permission.None, Permission.Read)); - [Fact] + [Fact(Skip = "Remove to run test")] public void GrantReadToRead() => Assert.Equal(Permission.Read, Permissions.Grant(Permission.Read, Permission.Read)); - [Fact] + [Fact(Skip = "Remove to run test")] public void GrantAllToNone() => Assert.Equal(Permission.All, Permissions.Grant(Permission.None, Permission.All)); - [Fact] + [Fact(Skip = "Remove to run test")] public void GrantDeleteToReadAndWrite() => Assert.Equal(Permission.All, Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)); - [Fact] + [Fact(Skip = "Remove to run test")] public void GrantReadAndWriteToNone() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Grant(Permission.None, Permission.Read | Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RevokeNoneFromRead() => Assert.Equal(Permission.Read, Permissions.Revoke(Permission.Read, Permission.None)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RevokeWriteFromWrite() => Assert.Equal(Permission.None, Permissions.Revoke(Permission.Write, Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RevokeDeleteFromAll() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Revoke(Permission.All, Permission.Delete)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RevokeReadAndWriteFromWriteAndDelete() => Assert.Equal(Permission.Delete, Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RevokeAllFromReadAndWrite() => Assert.Equal(Permission.None, Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckNoneForRead() => Assert.False(Permissions.Check(Permission.None, Permission.Read)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckWriteForWrite() => Assert.True(Permissions.Check(Permission.Write, Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckAllForWrite() => Assert.True(Permissions.Check(Permission.All, Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckReadAndWriteForRead() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckAllForReadAndWrite() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckReadAndWriteForReadAndWrite() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckReadAndWriteForReadAndDelete() => Assert.False(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)); - [Fact] + [Fact(Skip = "Remove to run test")] public void CheckReadAndWriteAndDeleteForAll() => Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); } \ No newline at end of file diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/enums/EnumsTests.cs index bcaf8a5c71..0da3573cfd 100644 --- a/exercises/concept/enums/EnumsTests.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -6,31 +6,31 @@ public class LogLineTests public void ParseError() => Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERROR]: Disk full")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ParseWarning() => Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WARNING]: Timezone not set")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ParseInfo() => Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INFO]: Timezone changed")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ParseUnknown() => Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[FATAL]: Crash!")); - [Fact] + [Fact(Skip = "Remove to run test")] public void OutputForShortLogForError() => Assert.Equal("4:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); - [Fact] + [Fact(Skip = "Remove to run test")] public void OutputForShortLogForWarning() => Assert.Equal("2:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); - [Fact] + [Fact(Skip = "Remove to run test")] public void OutputForShortLogForInfo() => Assert.Equal("1:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); - [Fact] + [Fact(Skip = "Remove to run test")] public void OutputForShortLogForUnknown() => Assert.Equal("0:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); } \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs index f1eb36fa96..42bef1d6b6 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs @@ -6,95 +6,95 @@ public class SavingsAccountTests public void MinimalFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void TinyFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(0.000001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void MaximumFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(999.9999m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void MinimalSecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void TinySecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void MaximumSecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(4_999.9990m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void MinimalThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0000m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void TinyThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void LargeThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_639_998.742909m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void MinimalNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.000001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void SmallNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.123m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void RegularNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-300.0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void LargeNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-152964.231m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForEmptyStartBalance() => Assert.Equal(0.0000m, SavingsAccount.AnnualBalanceUpdate(0.0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForSmallPositiveStartBalance() => Assert.Equal(0.000001005m, SavingsAccount.AnnualBalanceUpdate(0.000001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForAveragePositiveStartBalance() => Assert.Equal(1016.210000m, SavingsAccount.AnnualBalanceUpdate(1_000.0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForLargePositiveStartBalance() => Assert.Equal(1016.210101621m, SavingsAccount.AnnualBalanceUpdate(1_000.0001m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForHugePositiveStartBalance() => Assert.Equal(920352587.26744292868451875m, SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForSmallNegativeStartBalance() => Assert.Equal(-0.12695199m, SavingsAccount.AnnualBalanceUpdate(-0.123m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void AnnualBalanceUpdateForLargeNegativeStartBalance() => Assert.Equal(-157878.97174203m, SavingsAccount.AnnualBalanceUpdate(-152964.231m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void YearsBeforeDesiredBalanceForSmallStartBalance() => Assert.Equal(47, SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void YearsBeforeDesiredBalanceForAverageStartBalance() => Assert.Equal(6, SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void YearsBeforeDesiredBalanceForLargeStartBalance() => Assert.Equal(5, SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)); - [Fact] + [Fact(Skip = "Remove to run test")] public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() => Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); } \ No newline at end of file diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/numbers/NumbersTests.cs index bd1bf8987f..8545d8e36e 100644 --- a/exercises/concept/numbers/NumbersTests.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -6,39 +6,39 @@ public class AssemblyLineTests public void ProductionRatePerHourForSpeedZero() => Assert.Equal(0.0, AssemblyLine.ProductionRatePerHour(0)); - [Fact] + [Fact(Skip = "Remove to run test")] public void ProductionRatePerHourForSpeedOne() => Assert.Equal(221.0, AssemblyLine.ProductionRatePerHour(1)); - [Fact] + [Fact(Skip = "Remove to run test")] public void ProductionRatePerHourForSpeedFour() => Assert.Equal(884.0, AssemblyLine.ProductionRatePerHour(4)); - [Fact] + [Fact(Skip = "Remove to run test")] public void ProductionRatePerHourForSpeedSeven() => Assert.Equal(1392.3, AssemblyLine.ProductionRatePerHour(7)); - [Fact] + [Fact(Skip = "Remove to run test")] public void ProductionRatePerHourForSpeedNine() => Assert.Equal(1531.53, AssemblyLine.ProductionRatePerHour(9)); - [Fact] + [Fact(Skip = "Remove to run test")] public void WorkingItemsPerMinuteForSpeedZero() => Assert.Equal(0, AssemblyLine.WorkingItemsPerMinute(0)); - [Fact] + [Fact(Skip = "Remove to run test")] public void WorkingItemsPerMinuteForSpeedOne() => Assert.Equal(3, AssemblyLine.WorkingItemsPerMinute(1)); - [Fact] + [Fact(Skip = "Remove to run test")] public void WorkingItemsPerMinuteForSpeedFive() => Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); - [Fact] + [Fact(Skip = "Remove to run test")] public void WorkingItemsPerMinuteForSpeedEight() => Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); - [Fact] + [Fact(Skip = "Remove to run test")] public void WorkingItemsPerMinuteForSpeedTen() => Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); } diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/strings/StringsTests.cs index f654f0c284..131a301b0f 100644 --- a/exercises/concept/strings/StringsTests.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -6,43 +6,43 @@ public class LogLineTests public void ErrorMessage() => Assert.Equal("Stack overflow", LogLine.Message("[ERROR]: Stack overflow")); - [Fact] + [Fact(Skip = "Remove to run test")] public void WarningMessage() => Assert.Equal("Disk almost full", LogLine.Message("[WARNING]: Disk almost full")); - [Fact] + [Fact(Skip = "Remove to run test")] public void InfoMessage() => Assert.Equal("File moved", LogLine.Message("[INFO]: File moved")); - [Fact] + [Fact(Skip = "Remove to run test")] public void MessageWithLeadingAndTrailingWhiteSpace() => Assert.Equal("Timezone not set", LogLine.Message("[WARNING]: \tTimezone not set \r\n")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ErrorLogLevel() => Assert.Equal("error", LogLine.LogLevel("[ERROR]: Disk full")); - [Fact] + [Fact(Skip = "Remove to run test")] public void WarningLogLevel() => Assert.Equal("warning", LogLine.LogLevel("[WARNING]: Unsafe password")); - [Fact] + [Fact(Skip = "Remove to run test")] public void InfoLogLevel() => Assert.Equal("info", LogLine.LogLevel("[INFO]: Timezone changed")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ErrorReformat() => Assert.Equal("Segmentation fault (error)", LogLine.Reformat("[ERROR]: Segmentation fault")); - [Fact] + [Fact(Skip = "Remove to run test")] public void WarningReformat() => Assert.Equal("Decreased performance (warning)", LogLine.Reformat("[WARNING]: Decreased performance")); - [Fact] + [Fact(Skip = "Remove to run test")] public void InfoReformat() => Assert.Equal("Disk defragmented (info)", LogLine.Reformat("[INFO]: Disk defragmented")); - [Fact] + [Fact(Skip = "Remove to run test")] public void ReformatWithLeadingAndTrailingWhiteSpace() => Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); } \ No newline at end of file From e9a3b0704ae6d68774d3bbed6630344fd102694f Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:13:05 +0200 Subject: [PATCH 071/327] Add code syntax samples to numbers-floating-point exercise Add code syntax samples to numbers-floating-point exercise --- .../numbers-floating-point/.docs/introduction.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/numbers-floating-point/.docs/introduction.md index 891554f6e8..e9fb5e2b6d 100644 --- a/exercises/concept/numbers-floating-point/.docs/introduction.md +++ b/exercises/concept/numbers-floating-point/.docs/introduction.md @@ -10,4 +10,13 @@ C# has three floating-point types: As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded). -In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here. +In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here: + +```csharp +int x = 23; + +while (x > 10) +{ + // Execute logic if x > 10 +} +``` From fe83ae1a0eee054ace1cc3cdb88a063c3fb52885 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:13:24 +0200 Subject: [PATCH 072/327] Have student create a new DateTime instance Create a DateTime in the dates exercise Co-Authored-By: wolf99 --- exercises/concept/dates/.docs/hints.md | 7 +++++++ exercises/concept/dates/.docs/instructions.md | 11 ++++++++++- exercises/concept/dates/.meta/Example.cs | 3 +++ exercises/concept/dates/.meta/design.md | 4 +++- exercises/concept/dates/Dates.cs | 5 +++++ exercises/concept/dates/DatesTests.cs | 4 ++++ 6 files changed, 32 insertions(+), 2 deletions(-) diff --git a/exercises/concept/dates/.docs/hints.md b/exercises/concept/dates/.docs/hints.md index a71cdb7ff4..0c20e0e307 100644 --- a/exercises/concept/dates/.docs/hints.md +++ b/exercises/concept/dates/.docs/hints.md @@ -9,6 +9,7 @@ ### 2. Check if an appointment has already passed - `DateTime` objects can be compared using the default [comparison operators][docs.microsoft.com_datetime-operators]. +- There is a [property][docs.microsoft.com_datetime-properties] to retrieve the current date and time. ### 3. Check if appointment is in the afternoon @@ -19,9 +20,15 @@ - The tests are running as if running on a machine in the United States, which means that when converting a `DateTime` to a `string` will return dates and time in US format. - When converting a `DateTime` instance to a `string`, you can use either a [standard format string][docs.microsoft.com_standard-date-and-time-format-strings] or a [custom format string][docs.microsoft.com_custom-date-and-time-format-strings]. +### 5. Return the anniversary date + +- Use one of the various `DateTime` [constructors][constructors] to create a new `DateTime` instance. +- You can use one of the current date time's [properties][docs.microsoft.com_datetime-properties] to get the current year. + [docs.microsoft.com_parsing-date]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/parsing-datetime [docs.microsoft.com_datetime-operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netframework-4.8#operators [docs.microsoft.com_datetime-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.0#properties [docs.microsoft.com_standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings [docs.microsoft.com_custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings [csharp.net-dates-working-with-dates-time]: https://csharp.net-tutorials.com/data-types/working-with-dates-time/ +[constructors]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#constructors diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md index 1c4e37384c..42576a2c34 100644 --- a/exercises/concept/dates/.docs/instructions.md +++ b/exercises/concept/dates/.docs/instructions.md @@ -1,4 +1,4 @@ -In this exercise you'll be working on an appointment scheduler for a beauty salon in New York. +In this exercise you'll be working on an appointment scheduler for a beauty salon in New York that opened on September 15th in 2012. You have four tasks, which will all involve appointment dates. The dates and times will use one of the following four formats: @@ -44,3 +44,12 @@ Implement the `Appointment.Description` method that takes an appointment date an Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) // => "You have an appointment on Friday 29 March 2019 at 15:00." ``` + +### 5. Return the anniversary date + +Implement the `Appointment.AnniversaryDate` method that returns this year's anniversary date, which is September 15th: + +```csharp +Appointment.AnniversaryDate() +// => new DateTime(2019, 9, 15, 0, 0, 0) +``` diff --git a/exercises/concept/dates/.meta/Example.cs b/exercises/concept/dates/.meta/Example.cs index 563057c525..0db32e60af 100644 --- a/exercises/concept/dates/.meta/Example.cs +++ b/exercises/concept/dates/.meta/Example.cs @@ -13,4 +13,7 @@ public static bool IsAfternoonAppointment(DateTime appointmentDate) => public static string Description(DateTime appointmentDate) => $"You have an appointment on {appointmentDate}."; + + public static DateTime AnniversaryDate() => + new DateTime(DateTime.Now.Year, 9, 15); } \ No newline at end of file diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index 4e5ff8d393..1300304e4f 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -7,6 +7,7 @@ The goal of this exercise is to teach the student the basics of the Concept of D ## Learning objectives - Know of the existence of the `DateTime` type. +- Know how to create a `DateTime` instance. - Know how to get the current date. - Know of the individual, date-related properties. - Know how to access the current date. @@ -25,7 +26,7 @@ The goal of this exercise is to teach the student the basics of the Concept of D The Concepts this exercise unlocks are: -- `dates-basic`: know of the existence of the `DateTime` type; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa. +- `dates-basic`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa. - `time-basic`: know of the existence of the `DateTime` type; know of the individual, time-related properties. ## Prequisites @@ -34,6 +35,7 @@ This exercise's prerequisites Concepts are: - `numbers-basic`: comparing the hour against specific number values. - `strings-basic`: dates are parsed from and converted to strings. +- `classes-basic`: know how to call a constructor. ## Representer diff --git a/exercises/concept/dates/Dates.cs b/exercises/concept/dates/Dates.cs index 166c158d3d..208242dd26 100644 --- a/exercises/concept/dates/Dates.cs +++ b/exercises/concept/dates/Dates.cs @@ -21,4 +21,9 @@ public static string Description(DateTime appointmentDate) { throw new NotImplementedException("Please implement the Appointment.Description method"); } + + public static DateTime AnniversaryDate() + { + throw new NotImplementedException("Please implement the Appointment.AnniversaryDate method"); + } } \ No newline at end of file diff --git a/exercises/concept/dates/DatesTests.cs b/exercises/concept/dates/DatesTests.cs index f98d78cb45..ee15cfe026 100644 --- a/exercises/concept/dates/DatesTests.cs +++ b/exercises/concept/dates/DatesTests.cs @@ -104,6 +104,10 @@ public void DescriptionOnThursdayAfternoon() => public void DescriptionOnWednesdayMorning() => Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); + [Fact] + public void AnniversaryDate() => + Assert.Equal(new DateTime(DateTime.Now.Year, 9, 15), Appointment.AnniversaryDate()); + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] private class UseCultureAttribute : BeforeAfterTestAttribute { From e8841744758ee2704448661efe1e9c51ba003f61 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:13:54 +0200 Subject: [PATCH 073/327] Add code syntax samples to enums exercise Add code syntax samples to enums exercise --- exercises/concept/enums/.docs/after.md | 14 +++++++++++ exercises/concept/enums/.docs/introduction.md | 23 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md index 0457e964ed..6ffbd3f657 100644 --- a/exercises/concept/enums/.docs/after.md +++ b/exercises/concept/enums/.docs/after.md @@ -17,3 +17,17 @@ Users.WithStatus(Status.Active) For someone reading the code, the second (enum) version will be easier to comprehend. You should always consider using an enum whenever you want to model something as a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof. + +Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to any enum value: + +```csharp +public enum Status +{ + Inactive = 0, + Active = 1 +} + +Status status = (Status) 2; +status == Status.Inactive; // False +status == Status.Active; // False +``` diff --git a/exercises/concept/enums/.docs/introduction.md b/exercises/concept/enums/.docs/introduction.md index 90f298c775..6e93094ab0 100644 --- a/exercises/concept/enums/.docs/introduction.md +++ b/exercises/concept/enums/.docs/introduction.md @@ -1 +1,22 @@ -The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. +The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows: + +```csharp +public enum Season +{ + Spring, + Summer, + Autumn, + Winter +} +``` + +If not defined explicitly, enum members will automatically get assigned incrementing integer values, with the first value being zero. It is also possible to assign values explicitly: + +```csharp +public enum Answer +{ + Maybe = 1, + Yes = 3, + No = 5 +} +``` From 265a239f12976430e3f55975bc8d09ba489ddbbc Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:27:23 +0200 Subject: [PATCH 074/327] Add code syntax samples to numbers exercise Add code syntax samples to numbers exercise --- .../concept/numbers/.docs/introduction.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index b51e9f7f4a..98326b6827 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -14,4 +14,21 @@ C# has two types of numeric conversions: As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. -In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement. +In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement: + +```csharp +int x = 6; + +if (x <= 5) +{ + // Execute logic if x <= 5 +} +else if (x > 7) +{ + // Execute logic if x > 7 +} +else +{ + // Execute logic in all other cases +} +``` From cc2969a110baf8d8d2b71ca72d02ff05ac148e11 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:31:49 +0200 Subject: [PATCH 075/327] Add code syntax samples to enums-advanced exercise Add code syntax samples to enums-advanced exercise Co-Authored-By: wolf99 --- .../concept/enums-advanced/.docs/after.md | 4 +- .../enums-advanced/.docs/introduction.md | 42 ++++++++++++++++++- .../concept/enums-advanced/.meta/design.md | 1 + 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/enums-advanced/.docs/after.md index fc6aa85a20..196a644f59 100644 --- a/exercises/concept/enums-advanced/.docs/after.md +++ b/exercises/concept/enums-advanced/.docs/after.md @@ -1,4 +1,4 @@ -To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By assigning the values of the enum members such that each value has exactly one bit set to `1`, bitwise operators can be used to set or unset flags. +To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags. Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. @@ -8,6 +8,8 @@ Note that an enum member's value can refer to other enum members values. The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. +By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: + [docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ [or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- diff --git a/exercises/concept/enums-advanced/.docs/introduction.md b/exercises/concept/enums-advanced/.docs/introduction.md index ee57fa51ea..8fa44a4ace 100644 --- a/exercises/concept/enums-advanced/.docs/introduction.md +++ b/exercises/concept/enums-advanced/.docs/introduction.md @@ -1 +1,41 @@ -The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can mark the `enum` as one which constants are _flags_. By carefully assigning the values of each constant, one can use bitwise operators to add or remove references to one or more of the (flag) constants. +The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the `Flags` attribute. A _flags_ enum's constants are interpreted as bitwise _flags_. + +A flags enum can be defined as follows (using binary integer notation): + +```csharp +[Flags] +public enum PhoneFeatures +{ + Call = 0b00000001 + Text = 0b00000010 +} +``` + +A `PhoneFeatures` instance which value is `0b00000011` has both its `Call` _and_ `Text` flags set. + +To work with bits, C# supports the following operators: + +- `~`: bitwise complement +- `<<`: left shift +- `>>`: right shift +- `&`: logical AND +- `|`: logical OR +- `^`: logial XOR + +Here is an example how to use a bitwise operator: + +```csharp +1 << 2 +// => 4 +``` + +By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: + +```csharp +[Flags] +public enum PhoneFeatures : byte +{ + Call = 0b00000001 + Text = 0b00000010 +} +``` diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/enums-advanced/.meta/design.md index 10bd3c2968..74f8811bdc 100644 --- a/exercises/concept/enums-advanced/.meta/design.md +++ b/exercises/concept/enums-advanced/.meta/design.md @@ -30,6 +30,7 @@ This exercise's prerequisites Concepts are: - `enums-basic`: know how to define the `enum`. - `attributes-basic`: know how to annotate the enum with the `[Flags]` attribute. - `bitwise-operations`: know how to use bitwise operations to work with the flag enum values. +- `numbers-integers`: know of other integer types than `int` and know about binary integer literals ## Representer From 05219a6fad1298e44dae0d7d0a10f65be349538a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 08:32:15 +0200 Subject: [PATCH 076/327] Add code syntax samples to strings exercise Add code syntax samples to strings exercise --- exercises/concept/strings/.docs/introduction.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md index 335f05b7ea..db955821ba 100644 --- a/exercises/concept/strings/.docs/introduction.md +++ b/exercises/concept/strings/.docs/introduction.md @@ -1 +1,7 @@ -A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string. +A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance: + +```csharp +string fruit = "Apple"; +``` + +Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string. From fb8977fecba649affb82730afd7477a2dc997e08 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 09:18:10 +0200 Subject: [PATCH 077/327] Add basics exercise --- exercises/concept/basics/.docs/after.md | 62 +++++++++++++++++++ exercises/concept/basics/.docs/hints.md | 36 +++++++++++ .../concept/basics/.docs/instructions.md | 43 +++++++++++++ .../concept/basics/.docs/introduction.md | 47 ++++++++++++++ exercises/concept/basics/.meta/Example.cs | 13 ++++ exercises/concept/basics/.meta/config.json | 8 +++ exercises/concept/basics/.meta/design.md | 62 +++++++++++++++++++ exercises/concept/basics/Basics.cs | 10 +++ exercises/concept/basics/Basics.csproj | 13 ++++ exercises/concept/basics/BasicsTests.cs | 28 +++++++++ 10 files changed, 322 insertions(+) create mode 100644 exercises/concept/basics/.docs/after.md create mode 100644 exercises/concept/basics/.docs/hints.md create mode 100644 exercises/concept/basics/.docs/instructions.md create mode 100644 exercises/concept/basics/.docs/introduction.md create mode 100644 exercises/concept/basics/.meta/Example.cs create mode 100644 exercises/concept/basics/.meta/config.json create mode 100644 exercises/concept/basics/.meta/design.md create mode 100644 exercises/concept/basics/Basics.cs create mode 100644 exercises/concept/basics/Basics.csproj create mode 100644 exercises/concept/basics/BasicsTests.cs diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md new file mode 100644 index 0000000000..a12ae4b5f7 --- /dev/null +++ b/exercises/concept/basics/.docs/after.md @@ -0,0 +1,62 @@ +C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value. + +```csharp +int explicitVar = 10; // Explicitly typed +var implicitVar = 10; // Implicitly typed +``` + +The value of a variable can be assigned and updated using the [`=` operator][assignment]. Once defined, a variable's type can never change. + +```csharp +var count = 1; // Assign initial value +count = 2; // Update to new value + +// Compiler error when assigning different type +// count = false; +``` + +C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. It is common to specify an _access modifier_, which influences what other classes can use the class. The most common access modifier is `public`, which means that other classes can use this class. + +A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Like classes, an access modifier can be specified for methods. Values are returned from functions using the [`return` keyword][return]. + +```csharp +public class Calculator +{ + public int Add(int x, int y) + { + return x + y; + } +} +``` + +Invoking a method is done by specifying its class- and method name and passing arguments for each of the method's parameters. + +```csharp +var sum = Calculator.Add(1, 2); +``` + +If the method to be called is defined in the same class as the method that calls it, the class name can be omitted. + +If a method does not use any class _state_ (which is the case in this exercise), the method can be made _static_ using the `static` modifier. Similarly, if a class only has static methods, it too can be made static using the `static` modifier. + +```csharp +public static class Calculator +{ + public static int Multiply(int x, int y) + { + return x * y; + } +} +``` + +C# supports two types of [comments][comments]. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. + +Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators]. + +[assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator +[var]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var +[classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#declaring-classes +[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/methods +[return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator- +[comments]: https://www.w3schools.com/cs/cs_comments.asp diff --git a/exercises/concept/basics/.docs/hints.md b/exercises/concept/basics/.docs/hints.md new file mode 100644 index 0000000000..c8506ba7c8 --- /dev/null +++ b/exercises/concept/basics/.docs/hints.md @@ -0,0 +1,36 @@ +### General + +- An [integer value][integers] can be defined as one or more consecutive digits. + +### 1. Define the expected oven time in minutes + +- You need to define a [method][methods] without any arguments. +- You need to return an [integer][integers]. + +### 2. Calculate the remaining oven time in minutes + +- You need to define a [method][methods] with a single parameter. +- You have to [explicitly return an integer][return] from a method. +- The method's parameter is an [integer][integers]. +- You can use the [mathematical operator for subtraction][operators] to subtract values. + +### 3. Calculate the preparation time in minutes + +- You need to define a [method][methods] with a single parameter. +- You have to [explicitly return an integer][return] from a method. +- The method's parameter is an [integer][integers]. +- You can use the [mathematical operator for multiplicaton][operators] to multiply values. + +### 4. Calculate the total working time in minutes + +- You need to define a [method][methods] with two parameters. +- You have to [explicitly return an integer][return] from a method. +- The method's parameter is an [integer][integers]. +- You can [invoke][invocation] one of the other methods you've defined previously. +- You can use the [mathematical operator for addition][operators] to add values. + +[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/methods +[return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator- +[integers]: https://docs.microsoft.com/en-us/dotnet/api/system.int32?view=netcore-3.1#instantiating-an-int32-value +[invocation]: https://docs.microsoft.com/en-us/dotnet/csharp/methods#method-invocation diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/basics/.docs/instructions.md new file mode 100644 index 0000000000..db3260a0b4 --- /dev/null +++ b/exercises/concept/basics/.docs/instructions.md @@ -0,0 +1,43 @@ +In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book. + +You have four tasks, all related to the time spent cooking the lasasgna. + +### 1. Define the expected oven time in minutes + +Define the `Lasagna.ExpectedMinutesInOven` method that does not take any parameters and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: + +```csharp +var lasagna = new Lasagna(); +lasagna.ExpectedMinutesInOven(); +// => 40 +``` + +### 2. Calculate the remaining oven time in minutes + +Define the `Lasagna.RemainingMinutesInOven` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. + +```csharp +var lasagna = new Lasagna(); +lasagna.RemainingMinutesInOven(30); +// => 10 +``` + +### 3. Calculate the preparation time in minutes + +Define the `Lasagna.PreparationTimeInMinutes` method that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. + +```csharp +var lasagna = new Lasagna(); +lasagna.PreparationTimeInMinutes(2); +// => 4 +``` + +### 4. Calculate the total working time in minutes + +Define the `Lasagna.TotalTimeInMinutes` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. + +```csharp +var lasagna = new Lasagna(); +lasagna.TotalTimeInMinutes(3, 20); +// => 26 +``` diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/basics/.docs/introduction.md new file mode 100644 index 0000000000..f700f356e0 --- /dev/null +++ b/exercises/concept/basics/.docs/introduction.md @@ -0,0 +1,47 @@ +C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent: + +```csharp +int explicitVar = 10; // Explicitly typed +var implicitVar = 10; // Implicitly typed +``` + +Updating a variable's value is done through the `=` operator. Once defined, a variable's type can never change. + +```csharp +var count = 1; // Assign initial value +count = 2; // Update to new value + +// Compiler error when assigning different type +// count = false; +``` + +C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. It is common to specify an _access modifier_, which influences what other classes can use the class. The most common access modifier is `public`, which means that other classes can use this class. + +```csharp +public class Calculator +{ + // ... +} +``` + +A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Like classes, an access modifier can be specified for methods. Values are returned from functions using the `return` keyword. + +```csharp +public class Calculator +{ + public int Add(int x, int y) + { + return x + y; + } +} +``` + +Invoking a method is done by specifying its class- and method name and passing arguments for each of the method's parameters. + +```csharp +var sum = Calculator.Add(1, 2); +``` + +C# supports two types of comments. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. + +[object-oriented-programming]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/object-oriented-programming diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/basics/.meta/Example.cs new file mode 100644 index 0000000000..8213a773c3 --- /dev/null +++ b/exercises/concept/basics/.meta/Example.cs @@ -0,0 +1,13 @@ +public class Lasagna +{ + public int ExpectedMinutesInOven() => 40; + + public int RemainingMinutesInOven(int actualMinutesInOven) => + ExpectedMinutesInOven() - actualMinutesInOven; + + public int PreparationTimeInMinutes(int numberOfLayers) => + numberOfLayers * 2; + + public int TotalTimeInMinutes(int numberOfLayers, int actualMinutesInOven) => + PreparationTimeInMinutes(numberOfLayers) + actualMinutesInOven; +} \ No newline at end of file diff --git a/exercises/concept/basics/.meta/config.json b/exercises/concept/basics/.meta/config.json new file mode 100644 index 0000000000..44c72bd887 --- /dev/null +++ b/exercises/concept/basics/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md new file mode 100644 index 0000000000..23f9fe6109 --- /dev/null +++ b/exercises/concept/basics/.meta/design.md @@ -0,0 +1,62 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the basics of programming in C#. + +## Learning objectives + +- Know what a variable is. +- Know how to define a variable. +- Know how to update a variable. +- Know how to use type inference for variables. +- Know how to define a method. +- Know how to return a value from a method. +- Know how to call a method. +- Know that methods must be defined in classes. +- Know about the `public` access modifier. +- Know about the `static` modifier. +- Know how to define an integer. +- Know how to use mathematical operators on integers. +- Know how to define single- and multiline comments. + +## Out of scope + +- Naming rules for identifiers. +- Generic values. +- Memory and performance characteristics. +- Method overloads. +- Nested methods. +- Lambda's. +- Named parameters. +- Optional parameters. +- Classes. +- Organizing methods in namespaces. +- Visibility. + +## Concepts + +The Concepts this exercise unlocks are: + +- `variables-basic`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables. +- `methods-basic`: know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier. +- `integers-basic`: know how to define an integer; know how to use mathematical operators on integers. +- `comments-basic`: Know how to define single- and multiline comments. + +## Prequisites + +There are no prerequisites. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise could benefit from the following rules added to the the [analyzer][analyzer]: + +- Verify that the `RemainingMinutesInOven` method calls the `ExpectedMinutesInOven` method. +- Verify that the `TotalTimeInMinutes` method calls the `PreparationTimeInMinutes` method. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/basics/Basics.cs new file mode 100644 index 0000000000..767eef4df4 --- /dev/null +++ b/exercises/concept/basics/Basics.cs @@ -0,0 +1,10 @@ +public class Lasagna +{ + // TODO: define the 'ExpectedMinutesInOven' method + + // TODO: define the 'RemainingMinutesInOven' method + + // TODO: define the 'PreparationTimeInMinutes' method + + // TODO: define the 'TotalTimeInMinutes' method +} \ No newline at end of file diff --git a/exercises/concept/basics/Basics.csproj b/exercises/concept/basics/Basics.csproj new file mode 100644 index 0000000000..cfef7a3e96 --- /dev/null +++ b/exercises/concept/basics/Basics.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs new file mode 100644 index 0000000000..20b3e63fcf --- /dev/null +++ b/exercises/concept/basics/BasicsTests.cs @@ -0,0 +1,28 @@ +using Xunit; + +public class LasagnaTests +{ + [Fact] + public void ExpectedMinutesInOven() => + Assert.Equal(40, new Lasagna().ExpectedMinutesInOven()); + + [Fact(Skip = "Remove to run test")] + public void RemainingMinutesInOven() => + Assert.Equal(15, new Lasagna().RemainingMinutesInOven(25)); + + [Fact(Skip = "Remove to run test")] + public void PreparationTimeInMinutesForOneLayer() => + Assert.Equal(2, new Lasagna().PreparationTimeInMinutes(1)); + + [Fact(Skip = "Remove to run test")] + public void PreparationTimeInMinutesForMultipleLayers() => + Assert.Equal(8, new Lasagna().PreparationTimeInMinutes(4)); + + [Fact(Skip = "Remove to run test")] + public void TotalTimeInMinutesForOneLayer() => + Assert.Equal(32, new Lasagna().TotalTimeInMinutes(1, 30)); + + [Fact(Skip = "Remove to run test")] + public void TotalTimeInMinutesForMultipleLayers() => + Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); +} \ No newline at end of file From c12bed0b8a90303ca3c2d8da059fb23b75c1609e Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 2 Apr 2020 09:22:18 +0100 Subject: [PATCH 078/327] Add Properties Exercise Add Properties Exercise Co-authored-by: mikedamay Co-authored-by: Erik Schierboom Co-authored-by: Derk-Jan Karrenbeld Co-authored-by: mikedamay --- exercises/concept/properties/.docs/after.md | 79 ++++++ exercises/concept/properties/.docs/hints.md | 32 +++ .../concept/properties/.docs/instructions.md | 84 +++++++ .../concept/properties/.docs/introduction.md | 34 +++ exercises/concept/properties/.meta/Example.cs | 56 +++++ .../concept/properties/.meta/config.json | 25 ++ exercises/concept/properties/.meta/design.md | 234 ++++++++++++++++++ exercises/concept/properties/Properties.cs | 32 +++ .../concept/properties/Properties.csproj | 13 + .../concept/properties/PropertiesTests.cs | 64 +++++ 10 files changed, 653 insertions(+) create mode 100644 exercises/concept/properties/.docs/after.md create mode 100644 exercises/concept/properties/.docs/hints.md create mode 100644 exercises/concept/properties/.docs/instructions.md create mode 100644 exercises/concept/properties/.docs/introduction.md create mode 100644 exercises/concept/properties/.meta/Example.cs create mode 100644 exercises/concept/properties/.meta/config.json create mode 100644 exercises/concept/properties/.meta/design.md create mode 100644 exercises/concept/properties/Properties.cs create mode 100644 exercises/concept/properties/Properties.csproj create mode 100644 exercises/concept/properties/PropertiesTests.cs diff --git a/exercises/concept/properties/.docs/after.md b/exercises/concept/properties/.docs/after.md new file mode 100644 index 0000000000..db3c996ef3 --- /dev/null +++ b/exercises/concept/properties/.docs/after.md @@ -0,0 +1,79 @@ +The two main types of property are + +1. auto-implemented properties where the `get` and `set` accessors have no body. +They may or may not be explicitly initialized. For example: + ``` csharp + public int MyProperty {get; set;} = 42; + ``` +2. those where the accessors evaluate expressions and execute statements. The code can +be as simple as returning or assigning a backing field. For example: + ``` csharp + private int myField; + public int MyProperty + { + get { return myField; } + set { myField = value; } + } + ``` + + +There is considerable overlap of behaviour and power between properties and methods. +When they are not auto-implemented properties can contain any statement or expression +that can appear within the scope of the class. In a common case they are often described +as wrapping a backing field. +Although much of the time it is obvious whether to code behaviour as a property or method in a particular case it is +often a judgement call for the coder and in particular how much code should be +executed within the accessors. Validation in a set accessor and simple calculation or formatting in a +get accessor are commonly found: + +``` csharp +private float fraction; +public float Percentage +{ + get { return fraction * 100; } + set + { + if (value < 0 || value > 100) + { + throw new ArgumentException("Percentage must be between 0 and 100"); + } + fraction = value / 100; + } +} +``` + +In a similar way to other class members properties can have access levels. +Most often properties will have a non-private access level in line with +their essential purpose. Sometimes one of the accessors will have +a different access level to the property. In the case of `TareWeight` +under the rather artificial "security" constraint there was an opportunity +to have a public property with a private getter. This means that code external +to the class can set the value of the property but it can only be read (get) by code within +the class. + +``` csharp +public int ConfidentialValueUsedInternally {private get; set; } +``` + +Non-public set accessors are also supported but a more common case is where +the set accessor may be ommitted completely. This is maybe because +the value of the property is set in the class's constructor. + +``` csharp +public class MyClass +{ + public MyClass( int importantValue) + { + ConstructedValue = importantValue; + } + public int ConstructedValue {get;} +} +``` +This exercise has dealt with basic use of properties. You will find more advanced +topics in other exercises: +- expression bodied properties, get accessors and set accessors (covered by expression-bodied members) +- properties on interfaces (covered by Interfaces) +- properties/absract properties on abstract classes (covered by Inheritance) +- use of the `readonly` keyword with properties (covered by Immutability) +- static properties (covered by Statics) +- indexers (covered by Indexers) diff --git a/exercises/concept/properties/.docs/hints.md b/exercises/concept/properties/.docs/hints.md new file mode 100644 index 0000000000..3d28bfed69 --- /dev/null +++ b/exercises/concept/properties/.docs/hints.md @@ -0,0 +1,32 @@ +### General + +- [Properties][docs.microsoft.com-properties] +- [Using Properties][docs.microsoft.com-using-properties] + +### 1. Allow the weight to be set on the weighing machine + +A property with a private [backing field][docs.microsoft.com-properties-with-backing-fields] is appropriate here. + +### 2. Ensure that a negative input weight is rejected. + +Add [validation][stackoverflow.com-validating-properties] to the `InputWeight`'s `set` accessor to throw an exception. + +### 3. Allow the US weight to be retrieved + +A property can return a reference to an object. + +### 4. Allow the machine's units to be set to pounds + +`Units` is a good candidate for an [auto-implemented property][docs.microsoft.com-auto-implemented-properties]. + +### 5. Allow a tare adjustment to be applied to the weighing machine + +Accessors can have [different access levels][docs.microsoft.com-properties-and-restricted-access] to each other. + + +[docs.microsoft.com-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties +[docs.microsoft.com-using-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties +[docs.microsoft.com-properties-with-backing-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#properties-with-backing-fields +[stackoverflow.com-validating-properties]: https://stackoverflow.com/questions/4946227/validating-properties-in-c-sharp +[docs.microsoft.com-auto-implemented-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties +[docs.microsoft.com-properties-and-restricted-access]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/restricting-accessor-accessibility diff --git a/exercises/concept/properties/.docs/instructions.md b/exercises/concept/properties/.docs/instructions.md new file mode 100644 index 0000000000..1f7c79ec10 --- /dev/null +++ b/exercises/concept/properties/.docs/instructions.md @@ -0,0 +1,84 @@ +In this exercise you'll be modelling a weighing machine. + +The weight can be set and retrieved in pounds or kilograms and cannot be negative. + +The weight can be displayed in SI units or US units +, pounds and ounces. + +A tare adjustment can be applied to the weight (for instance to deduct the +weight of a container). This can be any value (even negative or a value that makes the display weight negative) +as there are doubts about the accuracy + of the weighing machine. For security reasons this value cannot be retrieved. + +Note that: +``` +display-weight = input-weight - tare-adjustment +``` + +Conversion ratios are as follows: +- 16 ounces to a pound +- 2.20462 kg to a pound + +For Example: +- 60 kilograms == 132.2772 ponds +- 132.2772 pounds == 132 pounds 4 ounces + +You have 5 tasks each of which requires you to implement one or +more properties: + +### 1 Allow the weight to be set on the weighing machine + +Implement the `WeigingMachine.InputWeight` property to allow the weight to be get and set: + +``` csharp +var wm = new WeighingMachine(); +wm.InputWeight = 60m; + +// => wm.InputWeight == 60m +``` + +### 2 Ensure that a negative input weight is rejected. + +Add validation to the `WeighingMachine.InputWeight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight: + +``` csharp +var wm = new WeighingMachine(); +wm.InputWeight = -10m; // Throws an ArgumentException +``` + +### 3 Allow the US weight to be retrieved + +Implement the `WeighingMachine.USDisplayWeight` property and the `USWeight` class: + +``` csharp +var wm = new WeighingMachine(); +wm.InputWeight = 60m; + +var usw = wm.USDisplayWeight; +// => usw.Pounds == 132 && usw.Ounces == 4 +``` + +### 4 Allow the machine's units to be set to pounds + +Implement the `WeighingMachine.Units` property: + +``` csharp +var wm = new WeighingMachine(); +wm.InputWeight = 175.5m; +wm.Units = Units.Pounds; + +var usw = wm.USDisplayWeight; +// => usw.Pounds == 175 && usw.Ounces == 8 +``` + +### 5 Allow a tare adjustment to be applied to the weighing machine + +Implement the `WeighingMachine.TareAdjustment` and `WeighingMachine.DisplayWeight` properties: + +``` csharp +var wm = new WeighingMachine(); +wm.InputWeight = 100m; +wm.TareAdjustment = 10m; + +// => wm.DisplayWeight == 90m +``` diff --git a/exercises/concept/properties/.docs/introduction.md b/exercises/concept/properties/.docs/introduction.md new file mode 100644 index 0000000000..76769a9f35 --- /dev/null +++ b/exercises/concept/properties/.docs/introduction.md @@ -0,0 +1,34 @@ +A property in C# is a member of a class that provides access to data within that class. +Callers can set or retrieve (get) the data. Properties can be either auto-implemented or +have a backing field. They comprise a set accessor and/or a get accessor. +In some other languages a "mutator" is roughly equivalent to a +a set accessor and an "accessor" is roughly equivalent to a set accessor although +the composition of the syntax is completely different. + +When setting a property the input value can be validated, formatted +or otherwise manipulated and in fact any programmatic operation accessible to code in the +class can be executed. + +Similarly when retrieving a property data can be calculated or formatted and again +any programmatic operation available to the class can be executed. + +Properties have access modifiers (`public`, `private` etc.) in the same way as other +class members but the set accessor may have an access level independent of the retrieve (get) +accessor and vice versa. A property doesn't have to have both accessors, it can have just one (either get or set). + +The basic syntax to express properties can take two forms: + +###### Field/Expression Backed Properties: +``` csharp +private int myField; +public int MyProperty +{ + get { return myfField; } + set { myField = value; } +} +``` +###### Auto-implemented Properties +``` +public int MyProperty { get; private set; } = 42; +``` +Initialisation is optional. diff --git a/exercises/concept/properties/.meta/Example.cs b/exercises/concept/properties/.meta/Example.cs new file mode 100644 index 0000000000..3023f6f48c --- /dev/null +++ b/exercises/concept/properties/.meta/Example.cs @@ -0,0 +1,56 @@ +using System; + +public enum Units +{ + Pounds, + Kilograms +} +public class WeighingMachine +{ + private const decimal POUNDS_PER_KILOGRAM = 2.20462m; + private decimal inputWeight; + + public Units Units { get; set; } = Units.Kilograms; + public decimal InputWeight + { + get { return inputWeight; } + set + { + if (value < 0) + { + throw new ArgumentException("weight cannot be negative"); + } + + inputWeight = value; + } + } + + public decimal DisplayWeight + { + get { return ApplyTareAdjustment(inputWeight); } + } + public USWeight USDisplayWeight + { + get + { + return new USWeight(WeightInPounds(DisplayWeight)); + } + } + public decimal TareAdjustment { set; private get; } + private decimal ApplyTareAdjustment(decimal weight) => weight - TareAdjustment; + private decimal WeightInPounds(decimal weight) => Units == Units.Kilograms ? weight * POUNDS_PER_KILOGRAM : weight; +} + +public class USWeight +{ + private const decimal OUNCES_PER_POUND = 16m; + + public USWeight(decimal displayWeightInPounds) + { + Pounds = (int)displayWeightInPounds; + Ounces = (int)(OUNCES_PER_POUND * (displayWeightInPounds - (int)displayWeightInPounds)); + } + + public int Pounds { get; } + public int Ounces { get; } +} diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json new file mode 100644 index 0000000000..50ed9c565c --- /dev/null +++ b/exercises/concept/properties/.meta/config.json @@ -0,0 +1,25 @@ +{ + "contributors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "exercises": { + "concept": [ + { + "slug": "properties", + "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350", + "concepts": [“properties-basic”], + "prerequisites": [ + "numbers-basic", + "numbers-floating-point", + "classes-basic", + "enums-basic", + "exceptions-basic", + "type-conversion-numbers" + ] + } + ] + } +}} diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md new file mode 100644 index 0000000000..a5b1723a5f --- /dev/null +++ b/exercises/concept/properties/.meta/design.md @@ -0,0 +1,234 @@ +# Design + +## Goal + +The goal of this exercise is to introduce the student to C# properties and to teach the student how the concept of properties is implemented in [C#][docs.microsoft.com-properties]. We'll teach the student about properties by having the student work with classes that expose contrasting forms of properties. The students will learn to work with properties with backing fields and auto-implemented properties. + +Properties are covered early in the C# track as their purpose and power can be shown with few dependencies (classes, access modifiers and fields of simple types). + + +## Learning objectives + +- Know what properties are and how they relate to fields and methods. +- Know what backing-field properties are. +- Know what auto-implemented properties are. +- Know what calculated properties are. +- Know how to use property accessors to customize visibility. +- Know how to define the different types of properties. + + +## Out of scope + +- expression bodied properties, get accessors and set accessors (covered by expression-bodied members) +- properties on interfaces (covered by Interfaces) +- properties/absract properties on abstract classes (covered by Inheritance) +- use of the `readonly` keyword with properties (covered by Immutability) +- static properties (covered by Statics) +- indexers (covered by Indexers) + +Note that students may choose to implement expression-bodied members. + +## Concepts + +This Concepts Exercise's concepts are: + +- `properties-basic`: know what properties are and how they relate to fields and methods; know what backing-field properties are; know what auto-implemented properties are; know what calculated properties are; know how to use property accessors to customize visibility; know how to define the different types of properties. + +## Prequisites + +- `integers-basic`: using the `int` type and using mathematical operators. +- `numbers-floating-point`: using the `decimal` type. +- `classes-basic`: defining classes and working with members. +- `enums-basic`: working with enums. +- `exceptions-basic`: throwing an exception. +- `type-conversion-numbers`: converting to an `int` + +Note that the values in the instructions' examples and tests +are selected specifically to avoid any question of rounding when converting +between float and int. Rounding and truncation will produce the +same result. + +Prerequisite Exercises - TBA + +## Resources to refer to + +### Hints + +- [Properties][docs.microsoft.com-properties] +- [Using Properties][docs.microsoft.com-using-properties] + +### After + +- [Properties][docs.microsoft.com-properties] +- [Using Properties][docs.microsoft.com-using-properties] + +As this is an introductory exercise, we should take care not to link to very advanced resources, to prevent overwhelming the student. + +## Representer + +TBC + +## Analyzer + +It is difficult to get the student to exercise all different aspects of +properties through tests alone. We need comments to address the following +practices: + +1. If `WeighingMachine.Units` is not auto-implemented +then the following comment should be made: "The appropriate form +for a property such as `WeighingMachine.Units` which has no validation or other processing required is +that for an auto-implemented property". - Approved with comment. + +2. If `WeighingMachine.DisplayWeight` has a non-private set accessor +then the following comment should be made: "It is not approprirate +for a property such as `WeighingMachine.DisplayWeight` which simply returns a value +to have a set accessor. That should be removed.". - Approved with comment. + +3. If `WeighingMachine.USDisplayWeight` has a non-private set accessor +then the following comment should be made: "It is not approprirate +for a property such as `USWeighingMachine.DisplayWeight` which simply returns a value +to have a set accessor. That should be removed.". - Approved with comment. + +4. If `USDisplayWeight.Pounds` has a non-private set accessor +then the following comment should be made: "It is not approprirate +for a property such as `USDisplayWeight.Pounds` which simply returns a value +to have a set accessor. That should be removed.". - Approved with comment. + +5. If `USDisplayWeight.Ounces` has a non-private set accessor +then the following comment should be made: "It is not approprirate +for a property such as `USDisplayWeight.Ounces` which simply returns a value +to have a set accessor. That should be removed.". - Approved with comment. + +6. If `WeighingMachine.TareAdjustement` is not an auto-implemented property +then the following commen should be made: "A succinct way of implementing +`WeighingMachine.TareAdjustment` is as an auto-implemented property with a +`private` get accessor". - Approved with comment. + +7. If `WeighingMachine.TareAdjustment` is an auto-implemented property +but the get accessor is non-private then the following comment should be made: +"A non-private set accessor is not appropriate for `WeighingMachine.TareAdjustment` +as the instructions stipulate that the value must not be available outside the +class". - Disapproved. + +## Implementing + +If you'd like to work on implementing this exercise, the first step is to let us know through a comment on this issue, to prevent multiple people from working on the same exercise. If you have any questions while implementing the exercise, please also post them as comments in this issue. + +Implementing the exercise means creating the following files: + +
+languages
+└── csharp
+    └── exercises
+        └── concept
+            └── properties
+                ├── .docs
+                |   ├── after.md
+                |   ├── hints.md
+                |   ├── instructions.md
+                |   └── introduction.md
+                ├── .meta
+                |   ├── design.md
+                |   └── Example.cs
+                ├── Properties.csproj
+                ├── Properties.cs
+                └── PropertiesTest.cs
+
+ +## Step 1: add .docs/introduction.md + +This file contains an introduction to the concept. It should be explicit about what the exercise teaches and maybe provide a brief introduction to the concepts, but not give away so much that the user doesn't have to do any work to solve the exercise. + +## Step 2: add .docs/instructions.md + +This file contains instructions for the exercise. It should explicitly explain what the user needs to do (define a method with the signature `X(...)` that takes an A and returns a Z), and provide at least one example usage of that function. If there are multiple tasks within the exercise, it should provide an example of each. + +## Step 3: add .docs/hints.md + +If the user gets stuck, we will allow them to click a button requesting a hint, which shows this file. We will softly discourage them using it. The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student. + +## Step 4: add .docs/after.md + +Once the user completes the exercise they will be shown this file, which gives them any bonus information or further reading about the concept taught. + +These files are also all described in the [concept exercises document][docs-concept-exercises]. + +## Step 5: update languages/csharp/config.json + +An entry should be added to the track's `config.json` file for the new concept exercise: + +```json +{ + ... + "exercises": { + "concept": [ + ... + { + "slug": "properties", + "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350, + "concepts": [“properties-basic”], + "prerequisites": [ + "numbers-basic", + "numbers-floating-point", + "classes-basic", + "enums-basic", + "exceptions-basic", + "type-conversion-numbers" + ] + } + ] + } +} +``` + +## Step 6: adding track-specific files + +These files are specific to the C# track: + +- `Properties.csproj`: the C# project file. +- `PropertiesTest.cs`: the test suite. +- `Properties.cs`. the stub implementation file, which is the starting point for students to work on the exercise. +- `.meta/Example.cs`: an example implementation that passes all the tests. + +Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-floating-point-numbers] for an example on what these files should look like. + +## Step 7: update the general concept document + +Not applicable for this concept + +## Step 8: updating list of implemented exercises + +- Add the exercise to the [list of implemented exercises][csharp-docs-concept-exercises]. + +## Step 9: add .meta/design.md: + +This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][meta-design]). This information can be extracted from this GitHub issue. + +### Inspiration + +When implementing this exericse, it can be very useful to look at already implemented C# exercises like the [strings][csharp-docs-concept-exercises-strings], [dates][csharp-docs-concept-exercises-dates] or [floating-point numbers][csharp-docs-concept-exercises-floating-point-numbers] exercises. + +[docs.microsoft.com-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties +[docs.microsoft.com-using-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties +[docs.microsoft.com-foreach-with-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[docs.microsoft.com-single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[docs.microsoft.com-implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[docs-v3]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md#exercise-structure +[docs-v3-types-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md +[docs-v3-types-collection]: https://github.com/exercism/v3/blob/master/reference/types/collection.md +[csharp-docs]: https://github.com/exercism/v3/blob/master/languages/csharp/README.md +[csharp-docs-concept-exercises-strings]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/strings +[csharp-docs-concept-exercises-dates]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates +[csharp-docs-concept-exercises-floating-point-numbers]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[csharp-analyzer]: https://github.com/exercism/csharp-analyzer +[csharp-representer]: https://github.com/exercism/csharp-representer +[csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md +[csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md +[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/after.md +[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/hints.md +[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/introduction.md +[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/instructions.md +[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/design.md +[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.meta/config.json +[csharp-docs-concept-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md +[referrence-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md diff --git a/exercises/concept/properties/Properties.cs b/exercises/concept/properties/Properties.cs new file mode 100644 index 0000000000..6a64e6bbf5 --- /dev/null +++ b/exercises/concept/properties/Properties.cs @@ -0,0 +1,32 @@ +using System; + +public enum Units +{ + Pounds, + Kilograms +} + +public class WeighingMachine +{ + // TODO: define the 'InputWeight' property + + // TODO: define the 'DisplayWeight' property + + // TODO: define the 'USDisplayWeight' property + + // TODO: define the 'TareAdjustment' property + + // TODO: define the 'Units' property +} +public struct USWeight +{ + + public USWeight(decimal weightInPounds) + { + throw new NotImplementedException("Please implement the USWeight classes' constructor"); + } + + // TODO: define the 'Pounds' property + + // TODO: define the 'Ounces' property +} diff --git a/exercises/concept/properties/Properties.csproj b/exercises/concept/properties/Properties.csproj new file mode 100644 index 0000000000..dbeb9f05e3 --- /dev/null +++ b/exercises/concept/properties/Properties.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/properties/PropertiesTests.cs new file mode 100644 index 0000000000..5ee5d18d43 --- /dev/null +++ b/exercises/concept/properties/PropertiesTests.cs @@ -0,0 +1,64 @@ +using System; +using Xunit; + +public class WeighingMachineTests +{ + [Fact] + public void Set_weight_and_get_weight() + { + var wm = new WeighingMachine(); + wm.InputWeight = 60m; + Assert.Equal(60m, wm.InputWeight, precision: 3); + } + + [Fact(Skip = "Remove to run test")] + public void Negative_weight_is_invalid() + { + var wm = new WeighingMachine(); + Assert.Throws(() => wm.InputWeight = -10); + } + + [Fact(Skip = "Remove to run test")] + public void Get_US_display_weight() + { + var wm = new WeighingMachine(); + wm.InputWeight = 60m; + Assert.Equal((132, 4), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); + } + + [Fact(Skip = "Remove to run test")] + public void Input_pounds_and_get_US_display_weight() + { + var wm = new WeighingMachine(); + wm.Units = Units.Pounds; + wm.InputWeight = 175.5m; + Assert.Equal((175, 8), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); + } + + [Fact(Skip = "Remove to run test")] + public void Apply_tare_adjustment_and_get_display_weight() + { + var wm = new WeighingMachine(); + wm.InputWeight = 100; + wm.TareAdjustment = 10; + Assert.Equal(90, wm.DisplayWeight); + } + + [Fact(Skip = "Remove to run test")] + public void Apply_negative_tare_adjustment() + { + var wm = new WeighingMachine(); + wm.InputWeight = 100; + wm.TareAdjustment = -10; + Assert.Equal(110, wm.DisplayWeight); + } + + [Fact(Skip = "Remove to run test")] + public void Apply_large_tare_adjustment_to_allow_negative_display_weight() + { + var wm = new WeighingMachine(); + wm.InputWeight = 100; + wm.TareAdjustment = 110; + Assert.Equal(-10, wm.DisplayWeight); + } +} From 77dd9b806403751b6dd7a2783f01c204d0faf2b6 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 2 Apr 2020 09:37:14 +0100 Subject: [PATCH 079/327] Corrected invalid Json token Some invisible nastiness had found its way into the string. --- exercises/concept/properties/.meta/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json index 50ed9c565c..c8764496c0 100644 --- a/exercises/concept/properties/.meta/config.json +++ b/exercises/concept/properties/.meta/config.json @@ -10,7 +10,7 @@ { "slug": "properties", "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350", - "concepts": [“properties-basic”], + "concepts": ["properties-basic"], "prerequisites": [ "numbers-basic", "numbers-floating-point", From 318fe85f17d5345ecdf3b1aaa9f47ec573c44d46 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 2 Apr 2020 12:48:30 +0200 Subject: [PATCH 080/327] Add parentheses to method names --- exercises/concept/basics/.docs/instructions.md | 8 ++++---- exercises/concept/basics/.meta/design.md | 4 ++-- exercises/concept/dates/.docs/instructions.md | 10 +++++----- exercises/concept/enums-advanced/.docs/instructions.md | 8 ++++---- exercises/concept/enums/.docs/instructions.md | 4 ++-- .../numbers-floating-point/.docs/instructions.md | 6 +++--- exercises/concept/numbers/.docs/instructions.md | 4 ++-- exercises/concept/strings/.docs/instructions.md | 6 +++--- 8 files changed, 25 insertions(+), 25 deletions(-) diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/basics/.docs/instructions.md index db3260a0b4..fd10cc0d57 100644 --- a/exercises/concept/basics/.docs/instructions.md +++ b/exercises/concept/basics/.docs/instructions.md @@ -4,7 +4,7 @@ You have four tasks, all related to the time spent cooking the lasasgna. ### 1. Define the expected oven time in minutes -Define the `Lasagna.ExpectedMinutesInOven` method that does not take any parameters and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: +Define the `Lasagna.ExpectedMinutesInOven()` method that does not take any parameters and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: ```csharp var lasagna = new Lasagna(); @@ -14,7 +14,7 @@ lasagna.ExpectedMinutesInOven(); ### 2. Calculate the remaining oven time in minutes -Define the `Lasagna.RemainingMinutesInOven` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. +Define the `Lasagna.RemainingMinutesInOven()` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. ```csharp var lasagna = new Lasagna(); @@ -24,7 +24,7 @@ lasagna.RemainingMinutesInOven(30); ### 3. Calculate the preparation time in minutes -Define the `Lasagna.PreparationTimeInMinutes` method that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. +Define the `Lasagna.PreparationTimeInMinutes()` method that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. ```csharp var lasagna = new Lasagna(); @@ -34,7 +34,7 @@ lasagna.PreparationTimeInMinutes(2); ### 4. Calculate the total working time in minutes -Define the `Lasagna.TotalTimeInMinutes` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. +Define the `Lasagna.TotalTimeInMinutes()` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. ```csharp var lasagna = new Lasagna(); diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index 23f9fe6109..a882924fd0 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -55,8 +55,8 @@ This exercise does not require any specific representation logic to be added to This exercise could benefit from the following rules added to the the [analyzer][analyzer]: -- Verify that the `RemainingMinutesInOven` method calls the `ExpectedMinutesInOven` method. -- Verify that the `TotalTimeInMinutes` method calls the `PreparationTimeInMinutes` method. +- Verify that the `RemainingMinutesInOven()` method calls the `ExpectedMinutesInOven()` method. +- Verify that the `TotalTimeInMinutes()` method calls the `PreparationTimeInMinutes()` method. [analyzer]: https://github.com/exercism/csharp-analyzer [representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/dates/.docs/instructions.md index 42576a2c34..531e60ef61 100644 --- a/exercises/concept/dates/.docs/instructions.md +++ b/exercises/concept/dates/.docs/instructions.md @@ -11,7 +11,7 @@ The tests will automatically set the culture to `en-US` - you don't have to set ### 1. Parse appointment date -Implement the `Appointment.Schedule` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: +Implement the `Appointment.Schedule()` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: ```csharp Appointment.Schedule("7/25/2019 13:45:00") @@ -20,7 +20,7 @@ Appointment.Schedule("7/25/2019 13:45:00") ### 2. Check if an appointment has already passed -Implement the `Appointment.HasPassed` method that takes an appointment date and checks if the appointment was somewhere in the past: +Implement the `Appointment.HasPassed()` method that takes an appointment date and checks if the appointment was somewhere in the past: ```csharp Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) @@ -29,7 +29,7 @@ Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) ### 3. Check if appointment is in the afternoon -Implement the `Appointment.IsAfternoonAppointment` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): +Implement the `Appointment.IsAfternoonAppointment()` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): ```csharp Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) @@ -38,7 +38,7 @@ Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) ### 4. Describe the time and date of the appointment -Implement the `Appointment.Description` method that takes an appointment date and returns a description of that date and time: +Implement the `Appointment.Description()` method that takes an appointment date and returns a description of that date and time: ```csharp Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) @@ -47,7 +47,7 @@ Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) ### 5. Return the anniversary date -Implement the `Appointment.AnniversaryDate` method that returns this year's anniversary date, which is September 15th: +Implement the `Appointment.AnniversaryDate()` method that returns this year's anniversary date, which is September 15th: ```csharp Appointment.AnniversaryDate() diff --git a/exercises/concept/enums-advanced/.docs/instructions.md b/exercises/concept/enums-advanced/.docs/instructions.md index ad31bcdfd0..2517485922 100644 --- a/exercises/concept/enums-advanced/.docs/instructions.md +++ b/exercises/concept/enums-advanced/.docs/instructions.md @@ -18,7 +18,7 @@ You have four tasks. First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions. -Then implement the `Permissions.Default` method to return the default permissions for a specific account type: +Then implement the `Permissions.Default()` method to return the default permissions for a specific account type: ```csharp Permissions.Default(AccountType.Guest) @@ -27,7 +27,7 @@ Permissions.Default(AccountType.Guest) ### 2. Grant a permission -Implement the `Permissions.Grant` method that grants (adds) a permission: +Implement the `Permissions.Grant()` method that grants (adds) a permission: ```csharp Permissions.Grant(current: Permission.None, grant: Permission.Read) @@ -36,7 +36,7 @@ Permissions.Grant(current: Permission.None, grant: Permission.Read) ### 3. Revoke a permission -Implement the `Permissions.Revoke` method that revokes (removes) a permission: +Implement the `Permissions.Revoke()` method that revokes (removes) a permission: ```csharp Permissions.Revoke(current: Permission.Read, grant: Permission.Read) @@ -45,7 +45,7 @@ Permissions.Revoke(current: Permission.Read, grant: Permission.Read) ### 4. Check for a permission -Implement the `Permissions.Check` method that takes the current account's permissions and checks if the account is authorized for a given permission: +Implement the `Permissions.Check()` method that takes the current account's permissions and checks if the account is authorized for a given permission: ```csharp Permissions.Check(current: Permission.Write, check: Permission.Read) diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index f7c8ad1fba..da895b18d0 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -18,7 +18,7 @@ Define a `LogLevel` enum that has three elements: - `Warning` - `Error` -Next, implement the `LogLine.ParseLogLevel` method to parse the log level of a log line: +Next, implement the `LogLine.ParseLogLevel()` method to parse the log level of a log line: ```csharp LogLine.ParseLogLevel("[INFO]: File deleted") @@ -45,7 +45,7 @@ The encoded log level is simple mapping of a log level to a number: - `Warning` -> `2` - `Error` -> `4` -Implement the `LogLine.OutputForShortLog` method that can output the shortened log line format: +Implement the `LogLine.OutputForShortLog()` method that can output the shortened log line format: ```csharp LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/numbers-floating-point/.docs/instructions.md index 09f7c3aea7..62ff6a311f 100644 --- a/exercises/concept/numbers-floating-point/.docs/instructions.md +++ b/exercises/concept/numbers-floating-point/.docs/instructions.md @@ -9,7 +9,7 @@ You have three tasks, each of which will deal your balance and its interest rate ### 1. Calculate the interest rate -Implement the `SavingsAccount.InterestRate` method to calculate the interest rate based on the specified balance: +Implement the `SavingsAccount.InterestRate()` method to calculate the interest rate based on the specified balance: ```csharp SavingsAccount.InterestRate(balance: 200.75m) @@ -20,7 +20,7 @@ Note that the value returned is a `float`. ### 2. Calculate the annual balance update -Implement the `SavingsAccount.AnnualBalanceUpdate` method to calculate the annual balance update, taking into account the interest rate: +Implement the `SavingsAccount.AnnualBalanceUpdate()` method to calculate the annual balance update, taking into account the interest rate: ```csharp SavingsAccount.AnnualBalanceUpdate(balance: 200.75m) @@ -31,7 +31,7 @@ Note that the value returned is a `decimal`. ### 3. Calculate the years before reaching the desired balance -Implement the `SavingsAccount.YearsBeforeDesiredBalance` method to calculate the minimum number of years required to reach the desired balance: +Implement the `SavingsAccount.YearsBeforeDesiredBalance()` method to calculate the minimum number of years required to reach the desired balance: ```csharp SavingsAccount.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88m) diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index 26e28a1bc6..259dbf0104 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -10,7 +10,7 @@ You have two tasks. ### 1. Calculate the production rate per hour -Implement the `AssemblyLine.ProductionRatePerHour` method to calculate the assembly line's production rate per hour, taking into account its success rate: +Implement the `AssemblyLine.ProductionRatePerHour()` method to calculate the assembly line's production rate per hour, taking into account its success rate: ```csharp AssemblyLine.ProductionRatePerHour(speed: 6) @@ -21,7 +21,7 @@ Note that the value returned is a `double`. ### 2. Calculate the number of working items produced per minute -Implement the `AssemblyLine.WorkingItemsPerMinute` method to calculate how many working cars are produced per minute: +Implement the `AssemblyLine.WorkingItemsPerMinute()` method to calculate how many working cars are produced per minute: ```csharp AssemblyLine.WorkingItemsPerMinute(speed: 6) diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index 507ee8e209..32ff33e09e 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -12,7 +12,7 @@ You have three tasks, each of which will take a log line and ask you to do somet ### 1. Get message from a log line -Implement the `LogLine.Message` method to return a log line's message: +Implement the `LogLine.Message()` method to return a log line's message: ```csharp LogLine.Message("[ERROR]: Invalid operation") @@ -28,7 +28,7 @@ LogLine.Message("[WARNING]: Disk almost full\r\n") ### 2. Get log level from a log line -Implement the `LogLine.LogLevel` method to return a log line's log level, which should be returned in lowercase: +Implement the `LogLine.LogLevel()` method to return a log line's log level, which should be returned in lowercase: ```csharp LogLine.LogLevel("[ERROR]: Invalid operation") @@ -37,7 +37,7 @@ LogLine.LogLevel("[ERROR]: Invalid operation") ### 3. Reformat a log line -Implement the `LogLine.Reformat` method that reformats the log line, putting the message first and the log level after it in parentheses: +Implement the `LogLine.Reformat()` method that reformats the log line, putting the message first and the log level after it in parentheses: ```csharp LogLine.Reformat("[INFO]: Operation completed") From 4ca05e1583b6698ad3defe20a201556a65de41ac Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 2 Apr 2020 12:56:06 +0200 Subject: [PATCH 081/327] Add syntax examples to after document of Strings exercise --- exercises/concept/strings/.docs/after.md | 29 ++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/exercises/concept/strings/.docs/after.md b/exercises/concept/strings/.docs/after.md index 5d7575c7c0..92a7332bef 100644 --- a/exercises/concept/strings/.docs/after.md +++ b/exercises/concept/strings/.docs/after.md @@ -1,10 +1,35 @@ -The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). +The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance: + +```csharp +string fruit = "Apple"; +``` Manipulating a string can be done by calling one of its [methods][methods] or [properties][properties]. As string values can never change after having been defined, all string manipulation methods will return a new string. A string is delimited by double quote (`"`) characters. Some special characters need [escaping][escaping] using the backslash (`\`) character. Strings can also be prefixed with the at (`@`) symbol, which makes it a [verbatim string][verbatim] that will ignore any escaped characters. -Finally, there are [many ways to concatenate a string][concatenation]. The simplest one is by using the [`+` operator][plus-operator]. For any string formatting more complex than simple concatenation, [string interpolation][interpolation] is preferred. To enable interpolation in a string, prefix it with the dollar (`$`) symbol. +```csharp +string escaped = "c:\\test.txt"; +string verbatim = @"c:\test.txt"; +escaped == verbatim; +// => true +``` + +Finally, there are [many ways to concatenate a string][concatenation]. The simplest one is by using the [`+` operator][plus-operator]. + +```csharp +string name = "Jane"; +"Hello " + name + "!"; +// => "Hello Jane!" +``` + +For any string formatting more complex than simple concatenation, [string interpolation][interpolation] is preferred. To enable interpolation in a string, prefix it with the dollar (`$`) symbol. + +```csharp +string name = "Jane"; +$"Hello {name}!"; +// => "Hello Jane!" +``` [concatenation]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings [interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation From 64045ee8bfa500d22cd127fef3a4871fa45a85a2 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 2 Apr 2020 15:48:36 +0200 Subject: [PATCH 082/327] Make after.md required --- reference/implementing-a-concept-exercise.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 2ca3d6c82e..2b076eef52 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -19,7 +19,7 @@ languages | ├── instructions.md | ├── introduction.md | ├── hints.md - | └── after.md (optional) + | └── after.md ├── .meta | |── config.json | |── design.md From a2de702576a7efa970bfad1bdb5ad1d341b72d38 Mon Sep 17 00:00:00 2001 From: wolf99 Date: Fri, 3 Apr 2020 07:43:31 +0100 Subject: [PATCH 083/327] Improve Skip string #1047 Co-authored-by: wolf99 --- exercises/concept/basics/BasicsTests.cs | 10 ++-- exercises/concept/dates/DatesTests.cs | 46 +++++++++---------- .../enums-advanced/EnumsAdvancedTests.cs | 42 ++++++++--------- exercises/concept/enums/EnumsTests.cs | 14 +++--- .../NumbersFloatingPointTests.cs | 46 +++++++++---------- exercises/concept/numbers/NumbersTests.cs | 18 ++++---- .../concept/properties/PropertiesTests.cs | 12 ++--- exercises/concept/strings/StringsTests.cs | 20 ++++---- 8 files changed, 104 insertions(+), 104 deletions(-) diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs index 20b3e63fcf..7441d3b5d5 100644 --- a/exercises/concept/basics/BasicsTests.cs +++ b/exercises/concept/basics/BasicsTests.cs @@ -6,23 +6,23 @@ public class LasagnaTests public void ExpectedMinutesInOven() => Assert.Equal(40, new Lasagna().ExpectedMinutesInOven()); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RemainingMinutesInOven() => Assert.Equal(15, new Lasagna().RemainingMinutesInOven(25)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void PreparationTimeInMinutesForOneLayer() => Assert.Equal(2, new Lasagna().PreparationTimeInMinutes(1)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void PreparationTimeInMinutesForMultipleLayers() => Assert.Equal(8, new Lasagna().PreparationTimeInMinutes(4)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void TotalTimeInMinutesForOneLayer() => Assert.Equal(32, new Lasagna().TotalTimeInMinutes(1, 30)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void TotalTimeInMinutesForMultipleLayers() => Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); } \ No newline at end of file diff --git a/exercises/concept/dates/DatesTests.cs b/exercises/concept/dates/DatesTests.cs index ee15cfe026..ea58e5d0fd 100644 --- a/exercises/concept/dates/DatesTests.cs +++ b/exercises/concept/dates/DatesTests.cs @@ -12,95 +12,95 @@ public class AppointmentTests public void ScheduleDateUsingOnlyNumbers() => Assert.Equal(new DateTime(2019, 07, 25, 13, 45, 0), Appointment.Schedule("7/25/2019 13:45:00")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ScheduleDateWithTextualMonth() => Assert.Equal(new DateTime(2019, 6, 3, 11, 30, 0), Appointment.Schedule("June 3, 2019 11:30:00")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ScheduleDateWithTextualMonthAndWeekday() => Assert.Equal(new DateTime(2019, 12, 5, 9, 0, 0), Appointment.Schedule("Thursday, December 5, 2019 09:00:00")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentOneYearAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentMonthsAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMonths(-8))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentDaysAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddDays(-23))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentHoursAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddHours(-12))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentMinutesAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-55))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentOneMinuteAgo() => Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-1))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentInOneMinute() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(1))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentInMinutes() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(5))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentInDays() => Assert.False(Appointment.HasPassed(DateTime.Now.AddDays(19))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentInMonths() => Assert.False(Appointment.HasPassed(DateTime.Now.AddMonths(10))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void HasPassedWithAppointmentInYears() => Assert.False(Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForEarlyMorningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForLateMorningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForNoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForEarlyAfternoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForLateAfternoonAppointment() => Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForEarlyEveningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void IsAfternoonAppointmentForLateEveningAppointment() => Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DescriptionOnFridayAfternoon() => Assert.Equal("You have an appointment on 3/29/2019 3:00:00 PM.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DescriptionOnThursdayAfternoon() => Assert.Equal("You have an appointment on 7/25/2019 1:45:00 PM.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DescriptionOnWednesdayMorning() => Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); diff --git a/exercises/concept/enums-advanced/EnumsAdvancedTests.cs b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs index 4210117966..6067964614 100644 --- a/exercises/concept/enums-advanced/EnumsAdvancedTests.cs +++ b/exercises/concept/enums-advanced/EnumsAdvancedTests.cs @@ -6,87 +6,87 @@ public class PermissionsTests public void DefaultForGuest() => Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DefaultForUser() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Default(AccountType.User)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DefaultForModerator() => Assert.Equal(Permission.Read | Permission.Write | Permission.Delete, Permissions.Default(AccountType.Moderator)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void DefaultForUnknown() => Assert.Equal(Permission.None, Permissions.Default((AccountType)123)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void GrantReadToNone() => Assert.Equal(Permission.Read, Permissions.Grant(Permission.None, Permission.Read)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void GrantReadToRead() => Assert.Equal(Permission.Read, Permissions.Grant(Permission.Read, Permission.Read)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void GrantAllToNone() => Assert.Equal(Permission.All, Permissions.Grant(Permission.None, Permission.All)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void GrantDeleteToReadAndWrite() => Assert.Equal(Permission.All, Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void GrantReadAndWriteToNone() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Grant(Permission.None, Permission.Read | Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RevokeNoneFromRead() => Assert.Equal(Permission.Read, Permissions.Revoke(Permission.Read, Permission.None)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RevokeWriteFromWrite() => Assert.Equal(Permission.None, Permissions.Revoke(Permission.Write, Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RevokeDeleteFromAll() => Assert.Equal(Permission.Read | Permission.Write, Permissions.Revoke(Permission.All, Permission.Delete)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RevokeReadAndWriteFromWriteAndDelete() => Assert.Equal(Permission.Delete, Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RevokeAllFromReadAndWrite() => Assert.Equal(Permission.None, Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckNoneForRead() => Assert.False(Permissions.Check(Permission.None, Permission.Read)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckWriteForWrite() => Assert.True(Permissions.Check(Permission.Write, Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckAllForWrite() => Assert.True(Permissions.Check(Permission.All, Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckReadAndWriteForRead() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckAllForReadAndWrite() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckReadAndWriteForReadAndWrite() => Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckReadAndWriteForReadAndDelete() => Assert.False(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void CheckReadAndWriteAndDeleteForAll() => Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); } \ No newline at end of file diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/enums/EnumsTests.cs index 0da3573cfd..4b0586295b 100644 --- a/exercises/concept/enums/EnumsTests.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -6,31 +6,31 @@ public class LogLineTests public void ParseError() => Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERROR]: Disk full")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ParseWarning() => Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WARNING]: Timezone not set")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ParseInfo() => Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INFO]: Timezone changed")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ParseUnknown() => Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[FATAL]: Crash!")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForError() => Assert.Equal("4:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForWarning() => Assert.Equal("2:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForInfo() => Assert.Equal("1:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForUnknown() => Assert.Equal("0:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); } \ No newline at end of file diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs index 42bef1d6b6..7dbc394739 100644 --- a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs +++ b/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs @@ -6,95 +6,95 @@ public class SavingsAccountTests public void MinimalFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void TinyFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(0.000001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MaximumFirstInterestRate() => Assert.Equal(0.5f, SavingsAccount.InterestRate(999.9999m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MinimalSecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void TinySecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MaximumSecondInterestRate() => Assert.Equal(1.621f, SavingsAccount.InterestRate(4_999.9990m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MinimalThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0000m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void TinyThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void LargeThirdInterestRate() => Assert.Equal(2.475f, SavingsAccount.InterestRate(5_639_998.742909m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MinimalNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.000001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void SmallNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.123m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void RegularNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-300.0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void LargeNegativeInterestRate() => Assert.Equal(-3.213f, SavingsAccount.InterestRate(-152964.231m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForEmptyStartBalance() => Assert.Equal(0.0000m, SavingsAccount.AnnualBalanceUpdate(0.0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForSmallPositiveStartBalance() => Assert.Equal(0.000001005m, SavingsAccount.AnnualBalanceUpdate(0.000001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForAveragePositiveStartBalance() => Assert.Equal(1016.210000m, SavingsAccount.AnnualBalanceUpdate(1_000.0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForLargePositiveStartBalance() => Assert.Equal(1016.210101621m, SavingsAccount.AnnualBalanceUpdate(1_000.0001m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForHugePositiveStartBalance() => Assert.Equal(920352587.26744292868451875m, SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForSmallNegativeStartBalance() => Assert.Equal(-0.12695199m, SavingsAccount.AnnualBalanceUpdate(-0.123m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void AnnualBalanceUpdateForLargeNegativeStartBalance() => Assert.Equal(-157878.97174203m, SavingsAccount.AnnualBalanceUpdate(-152964.231m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void YearsBeforeDesiredBalanceForSmallStartBalance() => Assert.Equal(47, SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void YearsBeforeDesiredBalanceForAverageStartBalance() => Assert.Equal(6, SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void YearsBeforeDesiredBalanceForLargeStartBalance() => Assert.Equal(5, SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() => Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); } \ No newline at end of file diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/numbers/NumbersTests.cs index 8545d8e36e..3712cad89d 100644 --- a/exercises/concept/numbers/NumbersTests.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -6,39 +6,39 @@ public class AssemblyLineTests public void ProductionRatePerHourForSpeedZero() => Assert.Equal(0.0, AssemblyLine.ProductionRatePerHour(0)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ProductionRatePerHourForSpeedOne() => Assert.Equal(221.0, AssemblyLine.ProductionRatePerHour(1)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ProductionRatePerHourForSpeedFour() => Assert.Equal(884.0, AssemblyLine.ProductionRatePerHour(4)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ProductionRatePerHourForSpeedSeven() => Assert.Equal(1392.3, AssemblyLine.ProductionRatePerHour(7)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ProductionRatePerHourForSpeedNine() => Assert.Equal(1531.53, AssemblyLine.ProductionRatePerHour(9)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedZero() => Assert.Equal(0, AssemblyLine.WorkingItemsPerMinute(0)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedOne() => Assert.Equal(3, AssemblyLine.WorkingItemsPerMinute(1)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedFive() => Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedEight() => Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedTen() => Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); } diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/properties/PropertiesTests.cs index 5ee5d18d43..0e38a8133b 100644 --- a/exercises/concept/properties/PropertiesTests.cs +++ b/exercises/concept/properties/PropertiesTests.cs @@ -11,14 +11,14 @@ public void Set_weight_and_get_weight() Assert.Equal(60m, wm.InputWeight, precision: 3); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Negative_weight_is_invalid() { var wm = new WeighingMachine(); Assert.Throws(() => wm.InputWeight = -10); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Get_US_display_weight() { var wm = new WeighingMachine(); @@ -26,7 +26,7 @@ public void Get_US_display_weight() Assert.Equal((132, 4), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Input_pounds_and_get_US_display_weight() { var wm = new WeighingMachine(); @@ -35,7 +35,7 @@ public void Input_pounds_and_get_US_display_weight() Assert.Equal((175, 8), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Apply_tare_adjustment_and_get_display_weight() { var wm = new WeighingMachine(); @@ -44,7 +44,7 @@ public void Apply_tare_adjustment_and_get_display_weight() Assert.Equal(90, wm.DisplayWeight); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Apply_negative_tare_adjustment() { var wm = new WeighingMachine(); @@ -53,7 +53,7 @@ public void Apply_negative_tare_adjustment() Assert.Equal(110, wm.DisplayWeight); } - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void Apply_large_tare_adjustment_to_allow_negative_display_weight() { var wm = new WeighingMachine(); diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/strings/StringsTests.cs index 131a301b0f..85f4aee7a9 100644 --- a/exercises/concept/strings/StringsTests.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -6,43 +6,43 @@ public class LogLineTests public void ErrorMessage() => Assert.Equal("Stack overflow", LogLine.Message("[ERROR]: Stack overflow")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WarningMessage() => Assert.Equal("Disk almost full", LogLine.Message("[WARNING]: Disk almost full")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void InfoMessage() => Assert.Equal("File moved", LogLine.Message("[INFO]: File moved")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void MessageWithLeadingAndTrailingWhiteSpace() => Assert.Equal("Timezone not set", LogLine.Message("[WARNING]: \tTimezone not set \r\n")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ErrorLogLevel() => Assert.Equal("error", LogLine.LogLevel("[ERROR]: Disk full")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WarningLogLevel() => Assert.Equal("warning", LogLine.LogLevel("[WARNING]: Unsafe password")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void InfoLogLevel() => Assert.Equal("info", LogLine.LogLevel("[INFO]: Timezone changed")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ErrorReformat() => Assert.Equal("Segmentation fault (error)", LogLine.Reformat("[ERROR]: Segmentation fault")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void WarningReformat() => Assert.Equal("Decreased performance (warning)", LogLine.Reformat("[WARNING]: Decreased performance")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void InfoReformat() => Assert.Equal("Disk defragmented (info)", LogLine.Reformat("[INFO]: Disk defragmented")); - [Fact(Skip = "Remove to run test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void ReformatWithLeadingAndTrailingWhiteSpace() => Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); } \ No newline at end of file From 197b49a7b1c60f9c491724f21abcfdd9f1a7d528 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 3 Apr 2020 13:32:50 +0200 Subject: [PATCH 084/327] Add syntax mention to after.md document description The after.md document should include newly introduced syntax. --- reference/examples/new-concept-exercise-arrays.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index 7f2def1fe4..da7d6a66a7 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -112,7 +112,7 @@ The hints should not spell out the solution, but instead point to a resource des ## Step 4: add .docs/after.md -Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. +Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. If the exercise introduced new syntax, syntax samples should be included. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. The above four files are also all described in the [concept exercises document][concept-exercises]. From 762e468582ce69b7c60920291f8a5913b59bb336 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 1 Apr 2020 16:16:51 +0200 Subject: [PATCH 085/327] Simplify concepts --- exercises/concept/basics/.meta/design.md | 5 +- exercises/concept/dates/.meta/design.md | 9 ++- .../concept/enums-advanced/.meta/design.md | 11 ++-- exercises/concept/enums/.meta/design.md | 10 +-- .../numbers-floating-point/.meta/design.md | 9 ++- exercises/concept/numbers/.meta/design.md | 9 +-- exercises/concept/properties/.meta/design.md | 63 +++++++++---------- exercises/concept/strings/.meta/design.md | 6 +- 8 files changed, 57 insertions(+), 65 deletions(-) diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index a882924fd0..eeda578515 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -38,10 +38,7 @@ The goal of this exercise is to teach the student the basics of programming in C The Concepts this exercise unlocks are: -- `variables-basic`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables. -- `methods-basic`: know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier. -- `integers-basic`: know how to define an integer; know how to use mathematical operators on integers. -- `comments-basic`: Know how to define single- and multiline comments. +- `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. ## Prequisites diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/dates/.meta/design.md index 1300304e4f..d9560910e1 100644 --- a/exercises/concept/dates/.meta/design.md +++ b/exercises/concept/dates/.meta/design.md @@ -26,16 +26,15 @@ The goal of this exercise is to teach the student the basics of the Concept of D The Concepts this exercise unlocks are: -- `dates-basic`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa. -- `time-basic`: know of the existence of the `DateTime` type; know of the individual, time-related properties. +- `datetime`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa; know of the existence of the `DateTime` type; know of the individual, time-related properties. ## Prequisites This exercise's prerequisites Concepts are: -- `numbers-basic`: comparing the hour against specific number values. -- `strings-basic`: dates are parsed from and converted to strings. -- `classes-basic`: know how to call a constructor. +- `numbers`: comparing the hour against specific number values. +- `strings`: dates are parsed from and converted to strings. +- `classes`: know how to call a constructor. ## Representer diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/enums-advanced/.meta/design.md index 74f8811bdc..e8a2134f87 100644 --- a/exercises/concept/enums-advanced/.meta/design.md +++ b/exercises/concept/enums-advanced/.meta/design.md @@ -12,6 +12,7 @@ The goal of this exercise is to teach the student advanced aspects of the Concep - Know how to set a flag on an enum value. - Know how to unset a flag on an enum value. - Know that an enum's underlying type can be changed. +- Know how to use bitwise operators to manipulate bits. ## Out of scope @@ -21,16 +22,16 @@ As this is an advanced exercise, there are no enum-related things that we should The Concepts this exercise unlocks are: -- `enums-advanced`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. +- `flag-enums`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. +- `bit-manipulation`: know how to use bitwise operators to manipulate bits. ## Prequisites This exercise's prerequisites Concepts are: -- `enums-basic`: know how to define the `enum`. -- `attributes-basic`: know how to annotate the enum with the `[Flags]` attribute. -- `bitwise-operations`: know how to use bitwise operations to work with the flag enum values. -- `numbers-integers`: know of other integer types than `int` and know about binary integer literals +- `enums`: know how to define the `enum`. +- `attributes`: know how to annotate the enum with the `[Flags]` attribute. +- `integers`: know of other integer types than `int` and know about binary integer literals. ## Representer diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index a6c5987962..24885b8972 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -24,18 +24,14 @@ After completing this exercise, the student should: The Concepts this exercise unlocks are: -- `enums-basic`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert a `string` to an `enum` and vice versa. -- `conditionals-ternary`: know how to conditionally execute code using the ternary operator; know when to use the ternary operator. +- `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert a `string` to an `enum` and vice versa. ## Prequisites This exercise's prerequisites Concepts are: -- `strings-basic`: log lines are `string` values. -- `numbers-basic`: enum values are assigned a numeric value. -- `generics`: generics are used to specify the enum type being parsed. -- `conditionals-if`: used to handle the case when the enum could not be parsed. -- `type-conversion-numbers`: casting the enum to an `int`. +- `strings`: log lines are `string` values. +- `conditionals`: used to conditionally execute code. ## Representer diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/numbers-floating-point/.meta/design.md index 7760150eda..5ce866204d 100644 --- a/exercises/concept/numbers-floating-point/.meta/design.md +++ b/exercises/concept/numbers-floating-point/.meta/design.md @@ -20,16 +20,15 @@ The goal of this exercise is to teach the student how the Concept of floating-po The Concepts this exercise unlocks are: -- `numbers-floating-point`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. -- `loops-while`: know how to write a `while` loop. +- `floating-point-numbers`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. +- `while-loops`: know how to write a `while` loop. ## Prequisites This exercise's prerequisites Concepts are: -- `numbers-basic`: define numbers and apply arithmetic and boolean logic to them. -- `type-conversion-numbers`: convert from one floating-point type to another. -- `conditionals-if`: conditionally execute code based on value of floating-point numbers. +- `numbers`: define numbers and apply arithmetic and boolean logic to them. +- `conditionals`: conditionally execute code based on value of floating-point numbers. ## Representer diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index 57813d6a63..f46d109b9d 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -22,13 +22,14 @@ The goal of this exercise is to teach the student how the Concept of Numbers is The Concepts this exercise unlocks are: -- `numbers-basic`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; now of basic operators such as multiplication and comparison. -- `type-conversion-numbers`: know how to convert from one numeric type to another; know what implicit and explicit conversions are. -- `conditionals-if`: know how to conditionally execute code using an `if` statement. +- `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; now of basic operators such as multiplication and comparison; know how to convert from one numeric type to another; know what implicit and explicit conversions are. +- `conditionals`: know how to conditionally execute code using an `if` statement. ## Prequisites -There are no prerequisites. +This exercise's prerequisites Concepts are: + +- `basics`: know how to define methods. ## Representer diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index a5b1723a5f..1ec6474bab 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -6,7 +6,6 @@ The goal of this exercise is to introduce the student to C# properties and to te Properties are covered early in the C# track as their purpose and power can be shown with few dependencies (classes, access modifiers and fields of simple types). - ## Learning objectives - Know what properties are and how they relate to fields and methods. @@ -16,7 +15,6 @@ Properties are covered early in the C# track as their purpose and power can be s - Know how to use property accessors to customize visibility. - Know how to define the different types of properties. - ## Out of scope - expression bodied properties, get accessors and set accessors (covered by expression-bodied members) @@ -32,20 +30,19 @@ Note that students may choose to implement expression-bodied members. This Concepts Exercise's concepts are: -- `properties-basic`: know what properties are and how they relate to fields and methods; know what backing-field properties are; know what auto-implemented properties are; know what calculated properties are; know how to use property accessors to customize visibility; know how to define the different types of properties. +- `properties`: know what properties are and how they relate to fields and methods; know what backing-field properties are; know what auto-implemented properties are; know what calculated properties are; know how to use property accessors to customize visibility; know how to define the different types of properties. ## Prequisites -- `integers-basic`: using the `int` type and using mathematical operators. -- `numbers-floating-point`: using the `decimal` type. -- `classes-basic`: defining classes and working with members. -- `enums-basic`: working with enums. -- `exceptions-basic`: throwing an exception. -- `type-conversion-numbers`: converting to an `int` +- `numbers`: using the `int` type and using mathematical operators and number conversions. +- `floating-point-numbers`: using the `decimal` type. +- `classes`: defining classes and working with members. +- `enums`: working with enums. +- `exceptions`: throwing an exception. Note that the values in the instructions' examples and tests are selected specifically to avoid any question of rounding when converting -between float and int. Rounding and truncation will produce the +between float and int. Rounding and truncation will produce the same result. Prerequisite Exercises - TBA @@ -71,44 +68,44 @@ TBC ## Analyzer It is difficult to get the student to exercise all different aspects of -properties through tests alone. We need comments to address the following +properties through tests alone. We need comments to address the following practices: 1. If `WeighingMachine.Units` is not auto-implemented -then the following comment should be made: "The appropriate form -for a property such as `WeighingMachine.Units` which has no validation or other processing required is -that for an auto-implemented property". - Approved with comment. + then the following comment should be made: "The appropriate form + for a property such as `WeighingMachine.Units` which has no validation or other processing required is + that for an auto-implemented property". - Approved with comment. 2. If `WeighingMachine.DisplayWeight` has a non-private set accessor -then the following comment should be made: "It is not approprirate -for a property such as `WeighingMachine.DisplayWeight` which simply returns a value -to have a set accessor. That should be removed.". - Approved with comment. + then the following comment should be made: "It is not approprirate + for a property such as `WeighingMachine.DisplayWeight` which simply returns a value + to have a set accessor. That should be removed.". - Approved with comment. 3. If `WeighingMachine.USDisplayWeight` has a non-private set accessor -then the following comment should be made: "It is not approprirate -for a property such as `USWeighingMachine.DisplayWeight` which simply returns a value -to have a set accessor. That should be removed.". - Approved with comment. + then the following comment should be made: "It is not approprirate + for a property such as `USWeighingMachine.DisplayWeight` which simply returns a value + to have a set accessor. That should be removed.". - Approved with comment. 4. If `USDisplayWeight.Pounds` has a non-private set accessor -then the following comment should be made: "It is not approprirate -for a property such as `USDisplayWeight.Pounds` which simply returns a value -to have a set accessor. That should be removed.". - Approved with comment. + then the following comment should be made: "It is not approprirate + for a property such as `USDisplayWeight.Pounds` which simply returns a value + to have a set accessor. That should be removed.". - Approved with comment. 5. If `USDisplayWeight.Ounces` has a non-private set accessor -then the following comment should be made: "It is not approprirate -for a property such as `USDisplayWeight.Ounces` which simply returns a value -to have a set accessor. That should be removed.". - Approved with comment. + then the following comment should be made: "It is not approprirate + for a property such as `USDisplayWeight.Ounces` which simply returns a value + to have a set accessor. That should be removed.". - Approved with comment. 6. If `WeighingMachine.TareAdjustement` is not an auto-implemented property -then the following commen should be made: "A succinct way of implementing -`WeighingMachine.TareAdjustment` is as an auto-implemented property with a -`private` get accessor". - Approved with comment. + then the following commen should be made: "A succinct way of implementing + `WeighingMachine.TareAdjustment` is as an auto-implemented property with a + `private` get accessor". - Approved with comment. 7. If `WeighingMachine.TareAdjustment` is an auto-implemented property -but the get accessor is non-private then the following comment should be made: -"A non-private set accessor is not appropriate for `WeighingMachine.TareAdjustment` -as the instructions stipulate that the value must not be available outside the -class". - Disapproved. + but the get accessor is non-private then the following comment should be made: + "A non-private set accessor is not appropriate for `WeighingMachine.TareAdjustment` + as the instructions stipulate that the value must not be available outside the + class". - Disapproved. ## Implementing diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index cc991ff060..8a22042688 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -21,11 +21,13 @@ The goal of this exercise is to teach the student the basics of the Concept of S The Concepts this exercise unlocks are: -- `strings-basic`: know of the existence of the `string` type; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string formatting. +- `strings`: know of the existence of the `string` type; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string formatting. ## Prequisites -There are no prerequisites. +This exercise's prerequisites Concepts are: + +- `basics`: know how to define methods. ## Representer From 361e6f62e8407eab7d49ebda9c9d0ef1986ef035 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 2 Apr 2020 14:38:31 +0200 Subject: [PATCH 086/327] Update exercise names --- .../{dates => datetimes}/.docs/after.md | 0 .../{dates => datetimes}/.docs/hints.md | 4 +-- .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{dates => datetimes}/.meta/Example.cs | 0 .../{dates => datetimes}/.meta/config.json | 0 .../{dates => datetimes}/.meta/design.md | 0 .../Dates.cs => datetimes/DateTimes.cs} | 0 .../DateTimes.csproj} | 0 .../DateTimesTests.cs} | 0 .../.docs/after.md | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 0 .../.meta/design.md | 0 .../FlagEnums.cs} | 0 .../FlagEnums.csproj} | 0 .../FlagEnumsTests.cs} | 0 .../.docs/after.md | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 0 .../.meta/design.md | 0 .../FloatingPointNumbers.cs} | 0 .../FloatingPointNumbers.csproj} | 0 .../FloatingPointNumbersTests.cs} | 0 .../concept/properties/.meta/config.json | 21 ++--------- exercises/concept/properties/.meta/design.md | 35 +++++++++---------- .../examples/new-concept-exercise-arrays.md | 2 +- reference/implementing-a-concept-exercise.md | 6 ++-- 34 files changed, 25 insertions(+), 43 deletions(-) rename exercises/concept/{dates => datetimes}/.docs/after.md (100%) rename exercises/concept/{dates => datetimes}/.docs/hints.md (90%) rename exercises/concept/{dates => datetimes}/.docs/instructions.md (100%) rename exercises/concept/{dates => datetimes}/.docs/introduction.md (100%) rename exercises/concept/{dates => datetimes}/.meta/Example.cs (100%) rename exercises/concept/{dates => datetimes}/.meta/config.json (100%) rename exercises/concept/{dates => datetimes}/.meta/design.md (100%) rename exercises/concept/{dates/Dates.cs => datetimes/DateTimes.cs} (100%) rename exercises/concept/{dates/Dates.csproj => datetimes/DateTimes.csproj} (100%) rename exercises/concept/{dates/DatesTests.cs => datetimes/DateTimesTests.cs} (100%) rename exercises/concept/{enums-advanced => flag-enums}/.docs/after.md (100%) rename exercises/concept/{enums-advanced => flag-enums}/.docs/hints.md (100%) rename exercises/concept/{enums-advanced => flag-enums}/.docs/instructions.md (100%) rename exercises/concept/{enums-advanced => flag-enums}/.docs/introduction.md (100%) rename exercises/concept/{enums-advanced => flag-enums}/.meta/Example.cs (100%) rename exercises/concept/{enums-advanced => flag-enums}/.meta/config.json (100%) rename exercises/concept/{enums-advanced => flag-enums}/.meta/design.md (100%) rename exercises/concept/{enums-advanced/EnumsAdvanced.cs => flag-enums/FlagEnums.cs} (100%) rename exercises/concept/{enums-advanced/EnumsAdvanced.csproj => flag-enums/FlagEnums.csproj} (100%) rename exercises/concept/{enums-advanced/EnumsAdvancedTests.cs => flag-enums/FlagEnumsTests.cs} (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.docs/after.md (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.docs/hints.md (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.docs/instructions.md (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.docs/introduction.md (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.meta/Example.cs (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.meta/config.json (100%) rename exercises/concept/{numbers-floating-point => floating-point-numbers}/.meta/design.md (100%) rename exercises/concept/{numbers-floating-point/NumbersFloatingPoint.cs => floating-point-numbers/FloatingPointNumbers.cs} (100%) rename exercises/concept/{numbers-floating-point/NumbersFloatingPoint.csproj => floating-point-numbers/FloatingPointNumbers.csproj} (100%) rename exercises/concept/{numbers-floating-point/NumbersFloatingPointTests.cs => floating-point-numbers/FloatingPointNumbersTests.cs} (100%) diff --git a/exercises/concept/dates/.docs/after.md b/exercises/concept/datetimes/.docs/after.md similarity index 100% rename from exercises/concept/dates/.docs/after.md rename to exercises/concept/datetimes/.docs/after.md diff --git a/exercises/concept/dates/.docs/hints.md b/exercises/concept/datetimes/.docs/hints.md similarity index 90% rename from exercises/concept/dates/.docs/hints.md rename to exercises/concept/datetimes/.docs/hints.md index 0c20e0e307..808ee7fcbd 100644 --- a/exercises/concept/dates/.docs/hints.md +++ b/exercises/concept/datetimes/.docs/hints.md @@ -1,6 +1,6 @@ ### General -- [Tutorial on dates and time by csharp.net][csharp.net-dates-working-with-dates-time] +- [Tutorial on dates and time by csharp.net][csharp.net-datetimes-working-with-datetimes-time] ### 1. Parse appointment date @@ -30,5 +30,5 @@ [docs.microsoft.com_datetime-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.0#properties [docs.microsoft.com_standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings [docs.microsoft.com_custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings -[csharp.net-dates-working-with-dates-time]: https://csharp.net-tutorials.com/data-types/working-with-dates-time/ +[csharp.net-datetimes-working-with-datetimes-time]: https://csharp.net-tutorials.com/data-types/working-with-datetimes-time/ [constructors]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#constructors diff --git a/exercises/concept/dates/.docs/instructions.md b/exercises/concept/datetimes/.docs/instructions.md similarity index 100% rename from exercises/concept/dates/.docs/instructions.md rename to exercises/concept/datetimes/.docs/instructions.md diff --git a/exercises/concept/dates/.docs/introduction.md b/exercises/concept/datetimes/.docs/introduction.md similarity index 100% rename from exercises/concept/dates/.docs/introduction.md rename to exercises/concept/datetimes/.docs/introduction.md diff --git a/exercises/concept/dates/.meta/Example.cs b/exercises/concept/datetimes/.meta/Example.cs similarity index 100% rename from exercises/concept/dates/.meta/Example.cs rename to exercises/concept/datetimes/.meta/Example.cs diff --git a/exercises/concept/dates/.meta/config.json b/exercises/concept/datetimes/.meta/config.json similarity index 100% rename from exercises/concept/dates/.meta/config.json rename to exercises/concept/datetimes/.meta/config.json diff --git a/exercises/concept/dates/.meta/design.md b/exercises/concept/datetimes/.meta/design.md similarity index 100% rename from exercises/concept/dates/.meta/design.md rename to exercises/concept/datetimes/.meta/design.md diff --git a/exercises/concept/dates/Dates.cs b/exercises/concept/datetimes/DateTimes.cs similarity index 100% rename from exercises/concept/dates/Dates.cs rename to exercises/concept/datetimes/DateTimes.cs diff --git a/exercises/concept/dates/Dates.csproj b/exercises/concept/datetimes/DateTimes.csproj similarity index 100% rename from exercises/concept/dates/Dates.csproj rename to exercises/concept/datetimes/DateTimes.csproj diff --git a/exercises/concept/dates/DatesTests.cs b/exercises/concept/datetimes/DateTimesTests.cs similarity index 100% rename from exercises/concept/dates/DatesTests.cs rename to exercises/concept/datetimes/DateTimesTests.cs diff --git a/exercises/concept/enums-advanced/.docs/after.md b/exercises/concept/flag-enums/.docs/after.md similarity index 100% rename from exercises/concept/enums-advanced/.docs/after.md rename to exercises/concept/flag-enums/.docs/after.md diff --git a/exercises/concept/enums-advanced/.docs/hints.md b/exercises/concept/flag-enums/.docs/hints.md similarity index 100% rename from exercises/concept/enums-advanced/.docs/hints.md rename to exercises/concept/flag-enums/.docs/hints.md diff --git a/exercises/concept/enums-advanced/.docs/instructions.md b/exercises/concept/flag-enums/.docs/instructions.md similarity index 100% rename from exercises/concept/enums-advanced/.docs/instructions.md rename to exercises/concept/flag-enums/.docs/instructions.md diff --git a/exercises/concept/enums-advanced/.docs/introduction.md b/exercises/concept/flag-enums/.docs/introduction.md similarity index 100% rename from exercises/concept/enums-advanced/.docs/introduction.md rename to exercises/concept/flag-enums/.docs/introduction.md diff --git a/exercises/concept/enums-advanced/.meta/Example.cs b/exercises/concept/flag-enums/.meta/Example.cs similarity index 100% rename from exercises/concept/enums-advanced/.meta/Example.cs rename to exercises/concept/flag-enums/.meta/Example.cs diff --git a/exercises/concept/enums-advanced/.meta/config.json b/exercises/concept/flag-enums/.meta/config.json similarity index 100% rename from exercises/concept/enums-advanced/.meta/config.json rename to exercises/concept/flag-enums/.meta/config.json diff --git a/exercises/concept/enums-advanced/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md similarity index 100% rename from exercises/concept/enums-advanced/.meta/design.md rename to exercises/concept/flag-enums/.meta/design.md diff --git a/exercises/concept/enums-advanced/EnumsAdvanced.cs b/exercises/concept/flag-enums/FlagEnums.cs similarity index 100% rename from exercises/concept/enums-advanced/EnumsAdvanced.cs rename to exercises/concept/flag-enums/FlagEnums.cs diff --git a/exercises/concept/enums-advanced/EnumsAdvanced.csproj b/exercises/concept/flag-enums/FlagEnums.csproj similarity index 100% rename from exercises/concept/enums-advanced/EnumsAdvanced.csproj rename to exercises/concept/flag-enums/FlagEnums.csproj diff --git a/exercises/concept/enums-advanced/EnumsAdvancedTests.cs b/exercises/concept/flag-enums/FlagEnumsTests.cs similarity index 100% rename from exercises/concept/enums-advanced/EnumsAdvancedTests.cs rename to exercises/concept/flag-enums/FlagEnumsTests.cs diff --git a/exercises/concept/numbers-floating-point/.docs/after.md b/exercises/concept/floating-point-numbers/.docs/after.md similarity index 100% rename from exercises/concept/numbers-floating-point/.docs/after.md rename to exercises/concept/floating-point-numbers/.docs/after.md diff --git a/exercises/concept/numbers-floating-point/.docs/hints.md b/exercises/concept/floating-point-numbers/.docs/hints.md similarity index 100% rename from exercises/concept/numbers-floating-point/.docs/hints.md rename to exercises/concept/floating-point-numbers/.docs/hints.md diff --git a/exercises/concept/numbers-floating-point/.docs/instructions.md b/exercises/concept/floating-point-numbers/.docs/instructions.md similarity index 100% rename from exercises/concept/numbers-floating-point/.docs/instructions.md rename to exercises/concept/floating-point-numbers/.docs/instructions.md diff --git a/exercises/concept/numbers-floating-point/.docs/introduction.md b/exercises/concept/floating-point-numbers/.docs/introduction.md similarity index 100% rename from exercises/concept/numbers-floating-point/.docs/introduction.md rename to exercises/concept/floating-point-numbers/.docs/introduction.md diff --git a/exercises/concept/numbers-floating-point/.meta/Example.cs b/exercises/concept/floating-point-numbers/.meta/Example.cs similarity index 100% rename from exercises/concept/numbers-floating-point/.meta/Example.cs rename to exercises/concept/floating-point-numbers/.meta/Example.cs diff --git a/exercises/concept/numbers-floating-point/.meta/config.json b/exercises/concept/floating-point-numbers/.meta/config.json similarity index 100% rename from exercises/concept/numbers-floating-point/.meta/config.json rename to exercises/concept/floating-point-numbers/.meta/config.json diff --git a/exercises/concept/numbers-floating-point/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md similarity index 100% rename from exercises/concept/numbers-floating-point/.meta/design.md rename to exercises/concept/floating-point-numbers/.meta/design.md diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs similarity index 100% rename from exercises/concept/numbers-floating-point/NumbersFloatingPoint.cs rename to exercises/concept/floating-point-numbers/FloatingPointNumbers.cs diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj b/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj similarity index 100% rename from exercises/concept/numbers-floating-point/NumbersFloatingPoint.csproj rename to exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj diff --git a/exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs similarity index 100% rename from exercises/concept/numbers-floating-point/NumbersFloatingPointTests.cs rename to exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json index c8764496c0..073e2e4b2b 100644 --- a/exercises/concept/properties/.meta/config.json +++ b/exercises/concept/properties/.meta/config.json @@ -4,22 +4,5 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ], - "exercises": { - "concept": [ - { - "slug": "properties", - "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350", - "concepts": ["properties-basic"], - "prerequisites": [ - "numbers-basic", - "numbers-floating-point", - "classes-basic", - "enums-basic", - "exceptions-basic", - "type-conversion-numbers" - ] - } - ] - } -}} + ] +} diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index 1ec6474bab..d99118f85f 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -162,15 +162,14 @@ An entry should be added to the track's `config.json` file for the new concept e ... { "slug": "properties", - "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350, - "concepts": [“properties-basic”], + "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350", + "concepts": ["properties"], "prerequisites": [ - "numbers-basic", - "numbers-floating-point", - "classes-basic", - "enums-basic", - "exceptions-basic", - "type-conversion-numbers" + "numbers", + "floating-point-numbers", + "classes", + "enums", + "exceptions" ] } ] @@ -187,7 +186,7 @@ These files are specific to the C# track: - `Properties.cs`. the stub implementation file, which is the starting point for students to work on the exercise. - `.meta/Example.cs`: an example implementation that passes all the tests. -Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-floating-point-numbers] for an example on what these files should look like. +Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-numbers-floating-point] for an example on what these files should look like. ## Step 7: update the general concept document @@ -203,7 +202,7 @@ This file contains information on the exercise's design, which includes things l ### Inspiration -When implementing this exericse, it can be very useful to look at already implemented C# exercises like the [strings][csharp-docs-concept-exercises-strings], [dates][csharp-docs-concept-exercises-dates] or [floating-point numbers][csharp-docs-concept-exercises-floating-point-numbers] exercises. +When implementing this exericse, it can be very useful to look at already implemented C# exercises like the [strings][csharp-docs-concept-exercises-strings], [dates][csharp-docs-concept-exercises-datetimes] or [floating-point numbers][csharp-docs-concept-exercises-numbers-floating-point] exercises. [docs.microsoft.com-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties [docs.microsoft.com-using-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties @@ -215,17 +214,17 @@ When implementing this exericse, it can be very useful to look at already implem [docs-v3-types-collection]: https://github.com/exercism/v3/blob/master/reference/types/collection.md [csharp-docs]: https://github.com/exercism/v3/blob/master/languages/csharp/README.md [csharp-docs-concept-exercises-strings]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/strings -[csharp-docs-concept-exercises-dates]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates -[csharp-docs-concept-exercises-floating-point-numbers]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[csharp-docs-concept-exercises-datetimes]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates +[csharp-docs-concept-exercises-numbers-floating-point]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/floating-point-numbers [csharp-analyzer]: https://github.com/exercism/csharp-analyzer [csharp-representer]: https://github.com/exercism/csharp-representer [csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md [csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md -[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/after.md -[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/hints.md -[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/introduction.md -[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/instructions.md -[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.docs/design.md -[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers-floating-point/.meta/config.json +[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/after.md +[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/hints.md +[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/introduction.md +[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/instructions.md +[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/design.md +[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.meta/config.json [csharp-docs-concept-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md [referrence-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md index da7d6a66a7..93b2982c5b 100644 --- a/reference/examples/new-concept-exercise-arrays.md +++ b/reference/examples/new-concept-exercise-arrays.md @@ -175,7 +175,7 @@ When implementing this exericse, it can be very useful to look at [already imple [reference-example]: https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations [analyzer]: https://github.com/exercism/csharp-analyzer [representer]: https://github.com/exercism/csharp-representer -[exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/floating-point-numbers [design-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/design.md [config.json-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/config.json [concept-exercises]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 2b076eef52..93411466a0 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -52,7 +52,7 @@ Some exercises could benefit from having an custom representation as generated b ## Inspiration -When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [dates][concept-exercise-dates] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. +When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [datetimes][concept-exercise-datetimes] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. ## Help @@ -63,6 +63,6 @@ If you have any questions regarding implementing the exercise, please post them [concept-exercises]: ../exercises/concept/README.md [how-to-implement-a-concept-exercise]: ../../../docs/maintainers/generic-how-to-implement-a-concept-exercise.md [concept-exercise-strings]: ../exercises/concept/strings -[concept-exercise-dates]: ../exercises/concept/dates -[concept-exercise-numbers-floating-point]: ../exercises/concept/numbers-floating-point +[concept-exercise-datetimes]: ../exercises/concept/datetimes +[concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers [reference]: ../../../reference From af855a71aa71d0b6df3e983c303158b0b257988a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 4 Apr 2020 12:23:21 +0200 Subject: [PATCH 087/327] Add set enum member value hints --- exercises/concept/enums/.docs/hints.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/enums/.docs/hints.md index 5098aa77c0..3ef256eed9 100644 --- a/exercises/concept/enums/.docs/hints.md +++ b/exercises/concept/enums/.docs/hints.md @@ -13,9 +13,11 @@ ### 3. Convert log line to short format +- One can [assign specific values to enum members][docs.microsoft.com_creating-an-enumeration-type]. - Converting an enum to a number can be done through [casting][docs.microsoft.com_enumeration-types-casting] or by using a [format string][docs.microsoft.com_system.enum.tostring]. [docs.microsoft.com-enumeration-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types [docs.microsoft.com_system.enum-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#methods [docs.microsoft.com_system.enum.tostring]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.tostring?view=netcore-3.0 [docs.microsoft.com_enumeration-types-casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#code-try-1 +[docs.microsoft.com_creating-an-enumeration-type]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#creating-an-enumeration-type From 1f6d77feb7542d276bf598926a4aa60343e65594 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 4 Apr 2020 18:32:47 +0200 Subject: [PATCH 088/327] =?UTF-8?q?Add=20syntax=20examples=20to=20after=20?= =?UTF-8?q?document=20of=20numbers-floating-point=20=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add syntax examples to after document of numbers-floating-point exercise Co-Authored-By: Rob Keim --- .../concept/floating-point-numbers/.docs/after.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/exercises/concept/floating-point-numbers/.docs/after.md b/exercises/concept/floating-point-numbers/.docs/after.md index b19ce1b9ce..b39fb2d598 100644 --- a/exercises/concept/floating-point-numbers/.docs/after.md +++ b/exercises/concept/floating-point-numbers/.docs/after.md @@ -4,11 +4,24 @@ Each floating-point type has its own [precision, approximate range and size][doc Some conversions between floating point types are [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but others are [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. +```csharp +decimal account = 125m * (decimal)1.2f; +``` + Always be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. -To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `true`. +To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `false`. + +```csharp +int x = 23; + +while (x > 10) +{ + // Execute logic if x > 10 +} +``` [docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions [docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions From 9bae13dffe0a991e724d95ac93ba385d84669b89 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 4 Apr 2020 18:36:14 +0200 Subject: [PATCH 089/327] Add syntax examples to after document of numbers exercise --- exercises/concept/numbers/.docs/after.md | 47 ++++++++++++++++++- .../concept/numbers/.docs/introduction.md | 2 + 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md index 7999c4ddbe..e7d3d0afe4 100644 --- a/exercises/concept/numbers/.docs/after.md +++ b/exercises/concept/numbers/.docs/after.md @@ -1,8 +1,21 @@ One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). -The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). +The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). -Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.). The result of a comparison can be used in `if` statements to conditionally execute code. +```csharp +int i = 123; +double d = 54.29; +``` + +Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.). + +```csharp +5 * 6; +// => 30 + +1.2 > 0.8 +// => true +``` When converting between numeric types, there are two types of numeric conversions: @@ -11,6 +24,36 @@ When converting between numeric types, there are two types of numeric conversion As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. +```csharp +int i = 9; +double d = 2.66; + +// Safe conversion, thus implicit conversion +double fromInt = i; + +// Potentially unsafe conversion, thus explicit conversion +int fromDouble = (int)d; +``` + +An `if` statement can be used to conditionally execute code. The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values. + +```csharp +int x = 6; + +if (x <= 5) +{ + // Execute logic if x <= 5 +} +else if (x > 7) +{ + // Execute logic if x > 7 +} +else +{ + // Execute logic in all other cases +} +``` + [arithmetic-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators [equality-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators [comparison-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index 98326b6827..68e508262f 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -32,3 +32,5 @@ else // Execute logic in all other cases } ``` + +The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values. From f27df29c1d38ac72efbb7b7fff362251b111a6bf Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 4 Apr 2020 18:39:28 +0200 Subject: [PATCH 090/327] Add syntax examples to after document of enums-advanced exercise --- exercises/concept/flag-enums/.docs/after.md | 73 ++++++++++++++++++- .../concept/flag-enums/.docs/introduction.md | 4 +- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/exercises/concept/flag-enums/.docs/after.md b/exercises/concept/flag-enums/.docs/after.md index 196a644f59..df389cdc45 100644 --- a/exercises/concept/flag-enums/.docs/after.md +++ b/exercises/concept/flag-enums/.docs/after.md @@ -1,15 +1,83 @@ To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags. -Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. +```csharp +[Flags] +public enum PhoneFeatures +{ + Call = 1, + Text = 2 +} +``` Besides using regular integers to set the flag enum members' values, one can also use [binary literals or the bitwise shift operator][binary-literals]. -Note that an enum member's value can refer to other enum members values. +```csharp +[Flags] +public enum PhoneFeaturesBinary +{ + Call = 0b00000001, + Text = 0b00000010 +} + +[Flags] +public enum PhoneFeaturesBitwiseShift +{ + Call = 1 << 0, + Text = 1 << 1 +} +``` + +An enum member's value can refer to other enum members values: + +```csharp +[Flags] +public enum PhoneFeatures +{ + Call = 0b00000001, + Text = 0b00000010, + All = Call | Text +} +``` + +Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. + +```csharp +var features = PhoneFeatures.Call; + +// Set the Text flag +features = features | PhoneFeatures.Text; + +features.HasFlag(PhoneFeatures.Call); // => true +features.HasFlag(PhoneFeatures.Text); // => true + +// Unset the Call flag +features = features & ~PhoneFeatures.Call; + +features.HasFlag(PhoneFeatures.Call); // => false +features.HasFlag(PhoneFeatures.Text); // => true +``` + +The bitwise operators can also be used as [compound assignments][compound-operators], which are a shorthand notation where `x = op y` can be written as `x op= y`: + +```csharp +var features = PhoneFeatures.Call; +features |= PhoneFeatures.Text; +features &= ~PhoneFeatures.Call; +``` The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: +```csharp +[Flags] +public enum PhoneFeatures : byte +{ + Call = 0b00000001, + Text = 0b00000010 +} +``` + [docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ [or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- @@ -17,3 +85,4 @@ By default, the `int` type is used for enum member values. One can use a differe [bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- [binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals [has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 +[compound-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment diff --git a/exercises/concept/flag-enums/.docs/introduction.md b/exercises/concept/flag-enums/.docs/introduction.md index 8fa44a4ace..970c568943 100644 --- a/exercises/concept/flag-enums/.docs/introduction.md +++ b/exercises/concept/flag-enums/.docs/introduction.md @@ -6,7 +6,7 @@ A flags enum can be defined as follows (using binary integer notation): [Flags] public enum PhoneFeatures { - Call = 0b00000001 + Call = 0b00000001, Text = 0b00000010 } ``` @@ -35,7 +35,7 @@ By default, the `int` type is used for enum member values. One can use a differe [Flags] public enum PhoneFeatures : byte { - Call = 0b00000001 + Call = 0b00000001, Text = 0b00000010 } ``` From c05b2153120f7acc7903d1b38c6529cc18b72e49 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 4 Apr 2020 18:59:03 +0200 Subject: [PATCH 091/327] Add syntax example to after document of Enums exercise --- exercises/concept/enums/.docs/after.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md index 6ffbd3f657..370f00ba89 100644 --- a/exercises/concept/enums/.docs/after.md +++ b/exercises/concept/enums/.docs/after.md @@ -2,15 +2,20 @@ You can use an enum whenever you have a fixed set of constant values. Using an e Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`. -Another benefit of enums are that they are very declarative. Compare the following two pieces of code: - ```csharp -Users.WithStatus(1) +public enum Season +{ + Spring, // Value is 0 + Summer = 2, // Value is 2 + Autumn, // Value is 3 + Winter = 7 // Value is 7 +} ``` -vs +Enums are very declarative. Compare the following two method calls: ```csharp +Users.WithStatus(1) Users.WithStatus(Status.Active) ``` From 2709085b8d0ecf623b14d0cdb81852412cbd38a7 Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Tue, 7 Apr 2020 12:34:29 +0100 Subject: [PATCH 092/327] Simplified basic-enums exercise by removing parsing Co-authored-by: Hani --- exercises/concept/enums/.docs/hints.md | 8 ++- exercises/concept/enums/.docs/instructions.md | 35 ++++++++----- exercises/concept/enums/.meta/Example.cs | 37 ++++++++++---- exercises/concept/enums/.meta/design.md | 8 +-- exercises/concept/enums/Enums.cs | 7 +-- exercises/concept/enums/EnumsTests.cs | 50 ++++++++++++++----- 6 files changed, 95 insertions(+), 50 deletions(-) diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/enums/.docs/hints.md index 3ef256eed9..e76126fcea 100644 --- a/exercises/concept/enums/.docs/hints.md +++ b/exercises/concept/enums/.docs/hints.md @@ -4,12 +4,12 @@ ### 1. Parse log level -- The `Enum` class has several [utility methods][docs.microsoft.com_system.enum-methods] to help with converting (parsing) a string to an enum. -- There is an option to ignore casing when parsing an enum. +- There is a [method to get a part of a string](https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=netcore-3.1). +- You can use a [`switch` statement](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch) to elegantly handle the various log levels. ### 2. Support unknown log level -- The `Enum` class' parsing methods also have similar methods that don't fail when not being able to parse an enum. +- There is a [special switch case](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case) that can be used to catch unspecified cases. ### 3. Convert log line to short format @@ -17,7 +17,5 @@ - Converting an enum to a number can be done through [casting][docs.microsoft.com_enumeration-types-casting] or by using a [format string][docs.microsoft.com_system.enum.tostring]. [docs.microsoft.com-enumeration-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types -[docs.microsoft.com_system.enum-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#methods -[docs.microsoft.com_system.enum.tostring]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.tostring?view=netcore-3.0 [docs.microsoft.com_enumeration-types-casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#code-try-1 [docs.microsoft.com_creating-an-enumeration-type]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#creating-an-enumeration-type diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index da895b18d0..180e054052 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -1,27 +1,33 @@ In this exercise you'll be processing log-lines. -Each log line is a string formatted as follows: `"[]: "`. +Each log line is a string formatted as follows: `"[]: "`. -There are three different log levels: +These are the different log levels: -- `INFO` -- `WARNING` -- `ERROR` +- `TRC` (trace) +- `DBG` (debug) +- `INF` (info) +- `WRN` (warning) +- `ERR` (error) +- `FTL` (fatal) You have three tasks. ### 1. Parse log level -Define a `LogLevel` enum that has three elements: +Define a `LogLevel` enum that has six elements corresponding to the above log levels. +- `Trace` +- `Debug` - `Info` - `Warning` - `Error` +- `Fatal` Next, implement the `LogLine.ParseLogLevel()` method to parse the log level of a log line: ```csharp -LogLine.ParseLogLevel("[INFO]: File deleted") +LogLine.ParseLogLevel("[INF]: File deleted") // => LogLevel.Info ``` @@ -30,7 +36,7 @@ LogLine.ParseLogLevel("[INFO]: File deleted") Unfortunately, occasionally some log lines have an unknown log level. To gracefully handle these log lines, add an `Unknown` element to the `LogLevel` enum which should be returned when parsing an unknown log level: ```csharp -LogLine.ParseLogLevel("[FATAL]: Invalid operation") +LogLine.ParseLogLevel("[XYZ]: Overly specific, out of context message") // => LogLevel.Unknown ``` @@ -40,14 +46,17 @@ The log level of a log line is quite verbose. To reduce the disk space needed to The encoded log level is simple mapping of a log level to a number: -- `Unknown` -> `0` -- `Info` -> `1` -- `Warning` -> `2` -- `Error` -> `4` +- `Trace` - `0` +- `Debug` - `1` +- `Info` - `4` +- `Warning` - `5` +- `Error` - `6` +- `Fatal` - `7` +- `Unknown` - `42` Implement the `LogLine.OutputForShortLog()` method that can output the shortened log line format: ```csharp LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") -// => "4:Stack overflow" +// => "6:Stack overflow" ``` diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/enums/.meta/Example.cs index c05fcbabdd..12189112a4 100644 --- a/exercises/concept/enums/.meta/Example.cs +++ b/exercises/concept/enums/.meta/Example.cs @@ -2,20 +2,37 @@ public enum LogLevel { - Unknown = 0, - Info = 1, - Warning = 2, - Error = 4 + Trace = 0, + Debug = 1, + Info = 4, + Warning = 5, + Error = 6, + Fatal = 7, + Unknown = 42 } public static class LogLine { - public static LogLevel ParseLogLevel(string logLine) => - Enum.TryParse(GetLogLevel(logLine), true, out LogLevel logLevel) ? logLevel : LogLevel.Unknown; + public static LogLevel ParseLogLevel(string logLine) { + + switch (logLine.Substring(1, 3)) { + case "TRC": + return LogLevel.Trace; + case "DBG": + return LogLevel.Debug; + case "INF": + return LogLevel.Info; + case "WRN": + return LogLevel.Warning; + case "ERR": + return LogLevel.Error; + case "FTL": + return LogLevel.Fatal; + default: + return LogLevel.Unknown; + } + } public static string OutputForShortLog(LogLevel logLevel, string message) => $"{(int)logLevel}:{message}"; - - private static string GetLogLevel(string logLine) => - logLine.Substring(1, logLine.IndexOf(']') - 1); -} \ No newline at end of file +} diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index 24885b8972..ed4c55cd35 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -12,26 +12,28 @@ After completing this exercise, the student should: - Know how to define enum members. - Know how to assign values to enum members. - Know how to get an enum's numeric value. -- Know how to convert a `string` to an `enum` and vice versa. +- Know how to use a `switch` statement to handle multiple conditions. ## Out of scope - Flag enums. - That an enum's underlying type can be changed. - Memory and performance characteristics. +- Parse `string` into an `enum`. ## Concepts The Concepts this exercise unlocks are: -- `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert a `string` to an `enum` and vice versa. +- `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert an `enum` to a `string`. +- `constant-switch`: know how to use a `switch` statement using constant values. ## Prequisites This exercise's prerequisites Concepts are: - `strings`: log lines are `string` values. -- `conditionals`: used to conditionally execute code. +- `conditionals`: know how to execute conditional logic. ## Representer diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs index 3bb60cd33b..2d5abe0bf8 100644 --- a/exercises/concept/enums/Enums.cs +++ b/exercises/concept/enums/Enums.cs @@ -13,9 +13,4 @@ public static string OutputForShortLog(LogLevel logLevel, string message) { throw new NotImplementedException("Please implement the LogLine.OutputForShortLog method"); } - - private static string GetLogLevel(string logLine) - { - return logLine.Substring(1, logLine.IndexOf(']') - 1); - } -} \ No newline at end of file +} diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/enums/EnumsTests.cs index 4b0586295b..928cde434c 100644 --- a/exercises/concept/enums/EnumsTests.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -3,34 +3,58 @@ public class LogLineTests { [Fact] - public void ParseError() => - Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERROR]: Disk full")); + public void ParseTrace() => + Assert.Equal(LogLevel.Trace, LogLine.ParseLogLevel("[TRC]: Line 84 - Console.WriteLine('Hello World');")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ParseDebug() => + Assert.Equal(LogLevel.Debug, LogLine.ParseLogLevel("[DBG]: ; expected")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ParseInfo() => + Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INF]: Timezone changed")); [Fact(Skip = "Remove this Skip property to run this test")] public void ParseWarning() => - Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WARNING]: Timezone not set")); + Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WRN]: Timezone not set")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ParseError() => + Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERR]: Disk full")); [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseInfo() => - Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INFO]: Timezone changed")); + public void ParseFatal() => + Assert.Equal(LogLevel.Fatal, LogLine.ParseLogLevel("[FTL]: Not enough memory")); [Fact(Skip = "Remove this Skip property to run this test")] public void ParseUnknown() => - Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[FATAL]: Crash!")); + Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[XYZ]: Gibberish message.. beep boop..")); [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForError() => - Assert.Equal("4:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); + public void OutputForShortLogForTrace() => + Assert.Equal("0:Line 13 - int myNum = 42;", LogLine.OutputForShortLog(LogLevel.Trace, "Line 13 - int myNum = 42;")); [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForWarning() => - Assert.Equal("2:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); + public void OutputForShortLogForDebug() => + Assert.Equal("1:The name 'LogLevel' does not exist in the current context", LogLine.OutputForShortLog(LogLevel.Debug, "The name 'LogLevel' does not exist in the current context")); [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForInfo() => - Assert.Equal("1:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); + Assert.Equal("4:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OutputForShortLogForWarning() => + Assert.Equal("5:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OutputForShortLogForError() => + Assert.Equal("6:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OutputForShortLogForFatal() => + Assert.Equal("7:Dumping all files", LogLine.OutputForShortLog(LogLevel.Fatal, "Dumping all files")); [Fact(Skip = "Remove this Skip property to run this test")] public void OutputForShortLogForUnknown() => - Assert.Equal("0:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); -} \ No newline at end of file + Assert.Equal("42:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); +} From 5996a984933bb4af4ce2ab36d87e74c4e524e221 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 9 Apr 2020 11:48:26 +0200 Subject: [PATCH 093/327] Add note about scope --- exercises/concept/basics/.docs/after.md | 2 ++ exercises/concept/basics/.docs/introduction.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md index a12ae4b5f7..a167fe687f 100644 --- a/exercises/concept/basics/.docs/after.md +++ b/exercises/concept/basics/.docs/after.md @@ -49,6 +49,8 @@ public static class Calculator } ``` +Scope in C# is defined between the `{` and `}` characters. + C# supports two types of [comments][comments]. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators]. diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/basics/.docs/introduction.md index f700f356e0..f51ff0b6be 100644 --- a/exercises/concept/basics/.docs/introduction.md +++ b/exercises/concept/basics/.docs/introduction.md @@ -42,6 +42,8 @@ Invoking a method is done by specifying its class- and method name and passing a var sum = Calculator.Add(1, 2); ``` +Scope in C# is defined between the `{` and `}` characters. + C# supports two types of comments. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. [object-oriented-programming]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/object-oriented-programming From 4d21fc3d21c6afd59ba2598ee16b6e8c973b0b84 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 9 Apr 2020 11:49:56 +0200 Subject: [PATCH 094/327] Change switch concept name --- exercises/concept/enums/.meta/design.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index ed4c55cd35..7a3ae322df 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -12,7 +12,7 @@ After completing this exercise, the student should: - Know how to define enum members. - Know how to assign values to enum members. - Know how to get an enum's numeric value. -- Know how to use a `switch` statement to handle multiple conditions. +- Know how to use the `switch` statement to do constant pattern matching. ## Out of scope @@ -26,7 +26,7 @@ After completing this exercise, the student should: The Concepts this exercise unlocks are: - `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert an `enum` to a `string`. -- `constant-switch`: know how to use a `switch` statement using constant values. +- `pattern-matching-constants`: know how to use the `switch` statement to do constant pattern matching. ## Prequisites From bd2f7b0821b4c19371d2ade7e802e2fef4ac40d0 Mon Sep 17 00:00:00 2001 From: Jeremy Walker Date: Thu, 9 Apr 2020 14:18:06 +0100 Subject: [PATCH 095/327] Add source and versioninfo to exercise config Co-authored-by: Sascha Mann Co-authored-by: Erik Schierboom --- reference/implementing-a-concept-exercise.md | 1 + 1 file changed, 1 insertion(+) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 93411466a0..69c53fc134 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -19,6 +19,7 @@ languages | ├── instructions.md | ├── introduction.md | ├── hints.md + | ├── source.md (required if there are third-party sources) | └── after.md ├── .meta | |── config.json From 1e4ae8a4b8e22c8cff2042dd8cf86db82cd62532 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 10 Apr 2020 11:32:51 +0200 Subject: [PATCH 096/327] Remove unused examples --- .../examples/new-concept-exercise-arrays.md | 186 ------------------ .../new-reference-doc-readonly-vs-const.md | 33 ---- 2 files changed, 219 deletions(-) delete mode 100644 reference/examples/new-concept-exercise-arrays.md delete mode 100644 reference/examples/new-reference-doc-readonly-vs-const.md diff --git a/reference/examples/new-concept-exercise-arrays.md b/reference/examples/new-concept-exercise-arrays.md deleted file mode 100644 index 93b2982c5b..0000000000 --- a/reference/examples/new-concept-exercise-arrays.md +++ /dev/null @@ -1,186 +0,0 @@ -This issue describes how to implement the `array` concept exercise for the C# track. - -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Arrays in [C#][arrays]. We'll use the array type to teach the student about some collection basics. The `array` collection type was chosen as the first collection type for the following reasons: - -- Arrays don't require the student to know about generics. -- Arrays are a common data type in many language. -- Arrays have a fixed length. No complexity in adding or removing elements. -- Arrays have a simple shorthand syntax. No need to understand how constructors work to define an array. - -## Learning objectives - -- Know of the existence of the `Array` type. -- Know how to define an array. -- Know how to access elements in an array by index. -- Know how to iterate over elements in an array. -- Know some basic array functions (like finding the index of an element in an array). - -## Out of scope - -- Multi-dimensional/jagged arrays. -- Memory and performance characteristics of arrays. -- Enumerables. -- Iterators. -- LINQ. - -## Concepts - -This Concepts Exercise's Concepts are: - -- `collections-basic`: know how to iterate over a collection. -- `arrays-basic`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). - -## Prequisites - -This Concept Exercise's prerequisites Concepts are: - -- `numbers-basic`: `int` values will be stored in the array and returned as output. - -## Resources to refer to - -### Hints - -- [Arrays][arrays]: basic information on strings. -- [Single-dimensional arrays][single-dimensional-arrays]: how to define a single-dimensional array. -- [Usings foreach with arrays][foreach]: how to iterate over an array using a `foreach` loop. - -### After - -- [Arrays][arrays]: basic information on strings. -- [Single-dimensional arrays][single-dimensional-arrays]: how to define a single-dimensional array. -- [Usings foreach with arrays][foreach]: how to iterate over an array using a `foreach` loop. -- [Implicitly typed arrays][implicitly-typed-arrays]: how to define implicitly-typed arrays. -- [Collections][collections]: how collections work. - -As this is an introductory exercise, we should take care not to link to very advanced resources, to prevent overwhelming the student. - -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise could benefit from having an [analyzer][analyzer] that can comment on: - -- Suggest using `foreach` if a `for` loop is used. - -## Implementing - -If you'd like to work on implementing this exercise, the first step is to let us know through a comment on this issue, to prevent multiple people from working on the same exercise. If you have any questions while implementing the exercise, please also post them as comments in this issue. - -Implementing the exercise means creating the following files: - -
-languages
-└── csharp
-    └── exercises
-        └── concept
-            └── arrays
-                ├── .docs
-                |   ├── after.md
-                |   ├── hints.md
-                |   ├── instructions.md
-                |   └── introduction.md
-                ├── .meta
-                |   ├── config.json
-                |   ├── design.md
-                |   └── Example.cs
-                ├── Arrays.csproj
-                ├── Arrays.cs
-                └── ArraysTests.cs
-
- -## Step 1: add .docs/introduction.md - -This file contains an introduction to the concept. It should make the exercise's learning goals explicit and provide a short introduction with enough detail for the student to complete the exercise. The aim is to give the student just enough context to figure out the solution themselves, as research has shown that self-discovery is the most effective learning experience. Using the proper technical terms in the descriptions will be helpful if the student wants to search for more information. If the exercise introduces new syntax, an example of the syntax should always be included; students should not need to search the web for examples of syntax. - -As an example, the introduction to a "strings" exercise might describe a string as just a "Sequence of Unicode characters" or a "series of bytes". Unless the student needs to understand more nuanced details in order to solve the exercise, this type of brief explanation (along with an example of its syntax) should be sufficient information for the student to solve the exercise. - -## Step 2: add .docs/instructions.md - -This file contains instructions for the exercise. It should explicitly explain what the student needs to do (define a method with the signature `X(...)` that takes an A and returns a Z), and provide at least one example usage of that function. If there are multiple tasks within the exercise, it should provide an example of each. - -## Step 3: add .docs/hints.md - -If the student gets stuck, we will allow them to click a button requesting a hint, which shows this file. This will not be a "recommended" path and we will (softly) discourage them using it unless they can't progress without it. As such, it's worth considering that the student reading it will be a little confused/overwhelmed and maybe frustrated. - -The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student. They might link to the docs of the functions that need to be used. - -The hints should not spell out the solution, but instead point to a resource describing the solution (e.g. linking to documentation for the function to use). - -## Step 4: add .docs/after.md - -Once the student completes the exercise they will be shown this file, which should provide them with a summary of what the exercise aimed to teach. If the exercise introduced new syntax, syntax samples should be included. This document can also link to any additional resources that might be interesting to the student in the context of the exercise. - -The above four files are also all described in the [concept exercises document][concept-exercises]. - -## Step 5: update languages/csharp/config.json - -An entry should be added to the track's `config.json` file for the new concept exercise: - -```json -{ - ... - "exercises": { - "concept": [ - ... - { - "slug": "arrays", - "uuid": "b6c532c9-1e89-4fbf-8f08-27f5befb5bb8", - "concepts": ["collections-basic", "arrays-basic"], - "prerequisites": ["numbers-basic"] - } - ] - } -} -``` - -## Step 6: adding track-specific files - -These files are specific to the C# track: - -- `Arrays.csproj`: the C# project file. -- `ArraysTests.cs`: the test suite. -- `Arrays.cs`. the stub implementation file, which is the starting point for students to work on the exercise. -- `.meta/Example.cs`: an example implementation that passes all the tests. - -Check out [an existing exercise][exercise-example] to see what these files should look like. - -## Step 7: update the general concept document - -Add the exercise to the [concept's shared document's][reference-array] `## Implementations` section ([example][reference-example]). - -## Step 8: updating list of implemented exercises - -- Add the exercise to the [list of implemented exercises][implemented-exercises]. - -## Step 9: add .meta/design.md: - -This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][design-example]). This information can be extracted from this GitHub issue. - -## Step 10: add .meta/config.json: - -This file contains meta information on the exercise, which currently only includes the exercise's contributors ([example][config.json-example]). - -### Inspiration - -When implementing this exericse, it can be very useful to look at [already implemented C# exercises][implemented-exercises]. You can also check the [general array concept documentation][reference-array] to see if any other languages have already implemented an arrays exercise. - -[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/master/docs/maintainers/generic-how-to-implement-a-concept-exercise.md -[implemented-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md#implemented-exercises -[reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs -[reference-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md -[reference-example]: https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer -[exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/floating-point-numbers -[design-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/design.md -[config.json-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/config.json -[concept-exercises]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md -[arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/ -[collections]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/collections -[foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays -[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays -[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays diff --git a/reference/examples/new-reference-doc-readonly-vs-const.md b/reference/examples/new-reference-doc-readonly-vs-const.md deleted file mode 100644 index c5b14282d2..0000000000 --- a/reference/examples/new-reference-doc-readonly-vs-const.md +++ /dev/null @@ -1,33 +0,0 @@ -# [C#] Add new reference document: readonly vs const - -This issue describes how to add a new [C# reference document][reference]: readonly vs const. - -## Description - -The goal of the new reference document is to explain the different between (`static`) `readonly` fields versus `const` fields, which is confusing to many students. - -The document should explain how the two approaches are different, taking into account: - -- What values they can be applied to. -- Readability aspects. -- Performance characteristics. -- Memory aspects. -- Generated IL code (optional). - -Based on the aforementioned differences, the document should provide guidance on when to use which approach and why. - -## Resources to refer to - -- [StackOverflow - static readonly vs const][stackoverflow.com] - -## Contributing - -To create the reference, please: - -- [Create the document at `language/csharp/reference/readonly-vs-const.md`][new-document]. -- Remove the corresponding TODO item in the [reference README][reference]. -- Add a link to the reference document in the [reference README][reference]. - -[stackoverflow.com]: https://stackoverflow.com/questions/755685/static-readonly-vs-const#755693 -[reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs -[new-document]: https://github.com/exercism/v3/new/master?filename=languages/csharp/reference/readonly-vs-const.md From 63a827974bc0479a601e359d978571465e997695 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 10 Apr 2020 14:06:33 +0200 Subject: [PATCH 097/327] Add reference to required reading in implementing guide [Docs] Add reference to required reading in implementing guide --- reference/implementing-a-concept-exercise.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 69c53fc134..3ec28f04f9 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -1,6 +1,14 @@ # How to implement a C# concept exercise -This document describes how to implement a concept exercise for the C# track. As this document is generic, the following placeholders are used: +This document describes how to implement a concept exercise for the C# track. + +**Please please please read the docs before starting.** Posting PRs without reading these docs will be a lot more frustrating for you during the review cycle, and exhaust Exercism's maintainers' time. So, before diving into the implementation, please read the following documents: + +- [The features of v3][docs-features-of-v3]. +- [Rationale for v3][docs-rationale-for-v3]. +- [What are concept exercise and how they are structured?][docs-concept-exercises] + +As this document is generic, the following placeholders are used: - ``: the name of the exercise in kebab-case (e.g. `anonymous-methods`). - ``: the name of the exercise in PascalCase (e.g. `AnonymousMethods`). @@ -63,6 +71,9 @@ If you have any questions regarding implementing the exercise, please post them [representer]: https://github.com/exercism/csharp-representer [concept-exercises]: ../exercises/concept/README.md [how-to-implement-a-concept-exercise]: ../../../docs/maintainers/generic-how-to-implement-a-concept-exercise.md +[docs-concept-exercises]: ../../../docs/concept-exercises.md +[docs-rationale-for-v3]: ../../../docs/rationale-for-v3.md +[docs-features-of-v3]: ../../../docs/features-of-v3.md [concept-exercise-strings]: ../exercises/concept/strings [concept-exercise-datetimes]: ../exercises/concept/datetimes [concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers From c53423293f3132d815a10ae038623f1a8a1017a9 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 10 Apr 2020 17:27:24 +0200 Subject: [PATCH 098/327] Use updated config.json format --- exercises/concept/basics/.meta/config.json | 5 +++-- exercises/concept/datetimes/.meta/config.json | 2 +- exercises/concept/enums/.meta/config.json | 2 +- exercises/concept/flag-enums/.meta/config.json | 2 +- exercises/concept/floating-point-numbers/.meta/config.json | 2 +- exercises/concept/numbers/.meta/config.json | 2 +- exercises/concept/properties/.meta/config.json | 2 +- exercises/concept/strings/.meta/config.json | 2 +- 8 files changed, 10 insertions(+), 9 deletions(-) diff --git a/exercises/concept/basics/.meta/config.json b/exercises/concept/basics/.meta/config.json index 44c72bd887..55ee67b595 100644 --- a/exercises/concept/basics/.meta/config.json +++ b/exercises/concept/basics/.meta/config.json @@ -1,8 +1,9 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "forked_from": ["fsharp/basics"] } diff --git a/exercises/concept/datetimes/.meta/config.json b/exercises/concept/datetimes/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/datetimes/.meta/config.json +++ b/exercises/concept/datetimes/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/enums/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/enums/.meta/config.json +++ b/exercises/concept/enums/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" diff --git a/exercises/concept/flag-enums/.meta/config.json b/exercises/concept/flag-enums/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/flag-enums/.meta/config.json +++ b/exercises/concept/flag-enums/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" diff --git a/exercises/concept/floating-point-numbers/.meta/config.json b/exercises/concept/floating-point-numbers/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/floating-point-numbers/.meta/config.json +++ b/exercises/concept/floating-point-numbers/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/numbers/.meta/config.json +++ b/exercises/concept/numbers/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json index 073e2e4b2b..315b869235 100644 --- a/exercises/concept/properties/.meta/config.json +++ b/exercises/concept/properties/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "mikedamay", "exercism_username": "mikedamay" diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json index 44c72bd887..6d4e44d872 100644 --- a/exercises/concept/strings/.meta/config.json +++ b/exercises/concept/strings/.meta/config.json @@ -1,5 +1,5 @@ { - "contributors": [ + "authors": [ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" From 38dd98d5b20f6790002fa5d0371401b829337ce2 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 14 Apr 2020 15:49:14 +0200 Subject: [PATCH 099/327] Add reference to Concept Exercise Anatomy video [Docs] Add reference to Concept Exercise Anatomy video --- reference/implementing-a-concept-exercise.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 3ec28f04f9..cb42fff566 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -8,6 +8,10 @@ This document describes how to implement a concept exercise for the C# track. - [Rationale for v3][docs-rationale-for-v3]. - [What are concept exercise and how they are structured?][docs-concept-exercises] +Please also watch the following video: + +- [The Anatomy of a Concept Exercise][anatomy-of-a-concept-exercise]. + As this document is generic, the following placeholders are used: - ``: the name of the exercise in kebab-case (e.g. `anonymous-methods`). @@ -74,6 +78,7 @@ If you have any questions regarding implementing the exercise, please post them [docs-concept-exercises]: ../../../docs/concept-exercises.md [docs-rationale-for-v3]: ../../../docs/rationale-for-v3.md [docs-features-of-v3]: ../../../docs/features-of-v3.md +[anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA [concept-exercise-strings]: ../exercises/concept/strings [concept-exercise-datetimes]: ../exercises/concept/datetimes [concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers From 0ddba0aebdc87cae2ef14e57237f238e82defc7c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 14 Apr 2020 16:02:21 +0200 Subject: [PATCH 100/327] Skip analyzer and representer steps if unclear --- reference/implementing-a-concept-exercise.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index cb42fff566..6cc4a53b6a 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -59,10 +59,14 @@ How to create the files common to all tracks is described in the [how to impleme Some exercises could benefit from having an exercise-specific [analyzer][analyzer]. If so, specify what analysis rules should be applied to this exercise and why. +Skip this step if you're not sure what to do. + ## Step 4: custom representation (optional) Some exercises could benefit from having an custom representation as generated by the [C# representer][representer]. If so, specify what changes to the representation should be applied and why. +Skip this step if you're not sure what to do. + ## Inspiration When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [datetimes][concept-exercise-datetimes] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. From d13466cddc8675b207486a258a2dad65b5945172 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 Apr 2020 08:40:56 +0200 Subject: [PATCH 101/327] Add equality operators to numbers exercise Add equality operators to numbers exercise --- exercises/concept/numbers/.docs/after.md | 11 +++++++---- exercises/concept/numbers/.docs/hints.md | 18 ++++++++++-------- .../concept/numbers/.docs/instructions.md | 7 ++++--- .../concept/numbers/.docs/introduction.md | 8 ++++---- exercises/concept/numbers/.meta/Example.cs | 5 ++++- exercises/concept/numbers/.meta/design.md | 4 ++-- exercises/concept/numbers/NumbersTests.cs | 10 +++++++++- 7 files changed, 40 insertions(+), 23 deletions(-) diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md index e7d3d0afe4..bd05dfab91 100644 --- a/exercises/concept/numbers/.docs/after.md +++ b/exercises/concept/numbers/.docs/after.md @@ -7,7 +7,7 @@ int i = 123; double d = 54.29; ``` -Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.). +Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.) and the [equality-][equality-operators] operator (`==`) and [inequality][equality-operators] operator (`!=`). ```csharp 5 * 6; @@ -15,6 +15,9 @@ Arithmetic is done using the standard [arithmetic operators][arithmetic-operator 1.2 > 0.8 // => true + +2 != 4 +// => true ``` When converting between numeric types, there are two types of numeric conversions: @@ -40,13 +43,13 @@ An `if` statement can be used to conditionally execute code. The condition of an ```csharp int x = 6; -if (x <= 5) +if (x == 5) { - // Execute logic if x <= 5 + // Execute logic if x equals 5 } else if (x > 7) { - // Execute logic if x > 7 + // Execute logic if x greater than 7 } else { diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md index b70f927abd..2aa7128a00 100644 --- a/exercises/concept/numbers/.docs/hints.md +++ b/exercises/concept/numbers/.docs/hints.md @@ -1,18 +1,20 @@ ### General -- [docs.microsoft.com numbers tutorial][tutorial-docs.microsoft-numbers] +- [Numbers tutorial][numbers]. ### 1. Calculate the production rate per second -- Determining the success rate can be done through a [conditional statement][tutorial-csharp.net-if-statement]. +- Determining the success rate can be done through a [conditional statement][if-statement]. - C# allows for multiplication to be applied to two different number types (such as an `int` and a `double`). It will automatically return the "largest" data type. - -[tutorial-docs.microsoft-numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local -[tutorial-csharp.net-if-statement]: https://csharp.net-tutorials.com/control-structures/if-statement/ +- Numbers can be compared using the built-in [comparison-][comparison-operators] and [equality operators][equality-operators]. ### 2. Calculate the number of working items produced per second -- Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that an `int` has less precision than a `double` so rounding has to be applied, also the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][docs-microsoft.com-convert] or [cast to an int][tutorial-dotnetperls.com-cast-int]. +- Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that an `int` has less precision than a `double` so rounding has to be applied, also the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][convert-class] or [cast to an int][cast-int]. -[docs-microsoft.com-convert]: https://docs.microsoft.com/en-us/dotnet/api/system.convert?view=netcore-3.0#examples -[tutorial-dotnetperls.com-cast-int]: https://www.dotnetperls.com/cast-int +[convert-class]: https://docs.microsoft.com/en-us/dotnet/api/system.convert?view=netcore-3.1#examples +[cast-int]: https://www.dotnetperls.com/cast-int +[numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local +[if-statement]: https://csharp.net-tutorials.com/control-structures/if-statement/ +[comparison-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators +[equality-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index 259dbf0104..2d3f92bbf8 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -4,7 +4,8 @@ At its lowest speed (`1`), `221` cars are produced each hour. The production inc - `1` to `4`: 100% success rate. - `5` to `8`: 90% success rate. -- `9` and `10`: 77% success rate. +- `9`: 80% success rate. +- `10`: 77% success rate. You have two tasks. @@ -13,7 +14,7 @@ You have two tasks. Implement the `AssemblyLine.ProductionRatePerHour()` method to calculate the assembly line's production rate per hour, taking into account its success rate: ```csharp -AssemblyLine.ProductionRatePerHour(speed: 6) +AssemblyLine.ProductionRatePerHour(6) // => 1193.4 ``` @@ -24,7 +25,7 @@ Note that the value returned is a `double`. Implement the `AssemblyLine.WorkingItemsPerMinute()` method to calculate how many working cars are produced per minute: ```csharp -AssemblyLine.WorkingItemsPerMinute(speed: 6) +AssemblyLine.WorkingItemsPerMinute(6) // => 19 ``` diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/numbers/.docs/introduction.md index 68e508262f..9b4bbf3aed 100644 --- a/exercises/concept/numbers/.docs/introduction.md +++ b/exercises/concept/numbers/.docs/introduction.md @@ -5,7 +5,7 @@ There are two different types of numbers in C#: The two most common numeric types in C# are `int` and `double`. An `int` is a 32-bit integer and a `double` is a 64-bit floating-point number. -Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators. +Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators and the equality (`==`) and inequality (`!=`) operators. C# has two types of numeric conversions: @@ -19,13 +19,13 @@ In this exercise you must conditionally execute logic. The most common way to do ```csharp int x = 6; -if (x <= 5) +if (x == 5) { - // Execute logic if x <= 5 + // Execute logic if x equals 5 } else if (x > 7) { - // Execute logic if x > 7 + // Execute logic if x greater than 7 } else { diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index 61974b04d6..10ce8a42b1 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -13,9 +13,12 @@ public static int WorkingItemsPerMinute(int speed) => private static double SuccessRate(int speed) { - if (speed >= 9) + if (speed == 10) return 0.77; + if (speed == 9) + return 0.8; + if (speed >= 5) return 0.9; diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index f46d109b9d..ed501403db 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -8,7 +8,7 @@ The goal of this exercise is to teach the student how the Concept of Numbers is - Know of the existence of the two most commonly used number types, `int` and `double`. - Understand that an `int` represents whole numbers, and a `double` represents floating-point numbers. -- Know of basic operators such as multiplication and comparison. +- Know of basic operators such as multiplication, comparison and equality. - Know how to convert from one numeric type to another; know what implicit and explicit conversions are. - Know how to conditionally execute code using an `if` statement. @@ -22,7 +22,7 @@ The goal of this exercise is to teach the student how the Concept of Numbers is The Concepts this exercise unlocks are: -- `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; now of basic operators such as multiplication and comparison; know how to convert from one numeric type to another; know what implicit and explicit conversions are. +- `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to convert from one numeric type to another; know what implicit and explicit conversions are. - `conditionals`: know how to conditionally execute code using an `if` statement. ## Prequisites diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/numbers/NumbersTests.cs index 3712cad89d..c089dd8f4f 100644 --- a/exercises/concept/numbers/NumbersTests.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -20,7 +20,11 @@ public void ProductionRatePerHourForSpeedSeven() => [Fact(Skip = "Remove this Skip property to run this test")] public void ProductionRatePerHourForSpeedNine() => - Assert.Equal(1531.53, AssemblyLine.ProductionRatePerHour(9)); + Assert.Equal(1591.2, AssemblyLine.ProductionRatePerHour(9)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ProductionRatePerHourForSpeedTen() => + Assert.Equal(1701.7, AssemblyLine.ProductionRatePerHour(10)); [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedZero() => @@ -38,6 +42,10 @@ public void WorkingItemsPerMinuteForSpeedFive() => public void WorkingItemsPerMinuteForSpeedEight() => Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); + [Fact(Skip = "Remove this Skip property to run this test")] + public void WorkingItemsPerMinuteForSpeedNine() => + Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(9)); + [Fact(Skip = "Remove this Skip property to run this test")] public void WorkingItemsPerMinuteForSpeedTen() => Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); From 2c7a415d8e33da8921fceae186f7f4f74384f1e3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 16 Apr 2020 09:48:25 +0200 Subject: [PATCH 102/327] Format using Prettier [Docs] Format using Prettier --- exercises/concept/properties/.docs/after.md | 41 ++++++++++--------- exercises/concept/properties/.docs/hints.md | 3 +- .../concept/properties/.docs/instructions.md | 19 +++++---- .../concept/properties/.docs/introduction.md | 14 ++++--- reference/exercise-concepts/gigasecond.md | 2 +- reference/exercise-concepts/high-scores.md | 16 +++++--- .../exercise-concepts/protein-translation.md | 2 +- reference/exercise-concepts/resistor-color.md | 4 +- 8 files changed, 57 insertions(+), 44 deletions(-) diff --git a/exercises/concept/properties/.docs/after.md b/exercises/concept/properties/.docs/after.md index db3c996ef3..8262879468 100644 --- a/exercises/concept/properties/.docs/after.md +++ b/exercises/concept/properties/.docs/after.md @@ -1,13 +1,13 @@ -The two main types of property are +The two main types of property are 1. auto-implemented properties where the `get` and `set` accessors have no body. -They may or may not be explicitly initialized. For example: - ``` csharp + They may or may not be explicitly initialized. For example: + ```csharp public int MyProperty {get; set;} = 42; ``` -2. those where the accessors evaluate expressions and execute statements. The code can -be as simple as returning or assigning a backing field. For example: - ``` csharp +2. those where the accessors evaluate expressions and execute statements. The code can + be as simple as returning or assigning a backing field. For example: + ```csharp private int myField; public int MyProperty { @@ -16,22 +16,21 @@ be as simple as returning or assigning a backing field. For example: } ``` - -There is considerable overlap of behaviour and power between properties and methods. +There is considerable overlap of behaviour and power between properties and methods. When they are not auto-implemented properties can contain any statement or expression -that can appear within the scope of the class. In a common case they are often described +that can appear within the scope of the class. In a common case they are often described as wrapping a backing field. Although much of the time it is obvious whether to code behaviour as a property or method in a particular case it is often a judgement call for the coder and in particular how much code should be -executed within the accessors. Validation in a set accessor and simple calculation or formatting in a +executed within the accessors. Validation in a set accessor and simple calculation or formatting in a get accessor are commonly found: -``` csharp +```csharp private float fraction; public float Percentage { get { return fraction * 100; } - set + set { if (value < 0 || value > 100) { @@ -44,33 +43,35 @@ public float Percentage In a similar way to other class members properties can have access levels. Most often properties will have a non-private access level in line with -their essential purpose. Sometimes one of the accessors will have -a different access level to the property. In the case of `TareWeight` +their essential purpose. Sometimes one of the accessors will have +a different access level to the property. In the case of `TareWeight` under the rather artificial "security" constraint there was an opportunity -to have a public property with a private getter. This means that code external +to have a public property with a private getter. This means that code external to the class can set the value of the property but it can only be read (get) by code within the class. -``` csharp +```csharp public int ConfidentialValueUsedInternally {private get; set; } ``` Non-public set accessors are also supported but a more common case is where -the set accessor may be ommitted completely. This is maybe because +the set accessor may be ommitted completely. This is maybe because the value of the property is set in the class's constructor. -``` csharp +```csharp public class MyClass { public MyClass( int importantValue) { ConstructedValue = importantValue; } - public int ConstructedValue {get;} + public int ConstructedValue {get;} } ``` -This exercise has dealt with basic use of properties. You will find more advanced + +This exercise has dealt with basic use of properties. You will find more advanced topics in other exercises: + - expression bodied properties, get accessors and set accessors (covered by expression-bodied members) - properties on interfaces (covered by Interfaces) - properties/absract properties on abstract classes (covered by Inheritance) diff --git a/exercises/concept/properties/.docs/hints.md b/exercises/concept/properties/.docs/hints.md index 3d28bfed69..9643459c3b 100644 --- a/exercises/concept/properties/.docs/hints.md +++ b/exercises/concept/properties/.docs/hints.md @@ -3,7 +3,7 @@ - [Properties][docs.microsoft.com-properties] - [Using Properties][docs.microsoft.com-using-properties] -### 1. Allow the weight to be set on the weighing machine +### 1. Allow the weight to be set on the weighing machine A property with a private [backing field][docs.microsoft.com-properties-with-backing-fields] is appropriate here. @@ -23,7 +23,6 @@ A property can return a reference to an object. Accessors can have [different access levels][docs.microsoft.com-properties-and-restricted-access] to each other. - [docs.microsoft.com-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties [docs.microsoft.com-using-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-properties [docs.microsoft.com-properties-with-backing-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties#properties-with-backing-fields diff --git a/exercises/concept/properties/.docs/instructions.md b/exercises/concept/properties/.docs/instructions.md index 1f7c79ec10..7bc8a680df 100644 --- a/exercises/concept/properties/.docs/instructions.md +++ b/exercises/concept/properties/.docs/instructions.md @@ -6,31 +6,34 @@ The weight can be displayed in SI units or US units , pounds and ounces. A tare adjustment can be applied to the weight (for instance to deduct the -weight of a container). This can be any value (even negative or a value that makes the display weight negative) +weight of a container). This can be any value (even negative or a value that makes the display weight negative) as there are doubts about the accuracy - of the weighing machine. For security reasons this value cannot be retrieved. +of the weighing machine. For security reasons this value cannot be retrieved. Note that: + ``` display-weight = input-weight - tare-adjustment ``` Conversion ratios are as follows: + - 16 ounces to a pound - 2.20462 kg to a pound For Example: + - 60 kilograms == 132.2772 ponds - 132.2772 pounds == 132 pounds 4 ounces You have 5 tasks each of which requires you to implement one or more properties: -### 1 Allow the weight to be set on the weighing machine +### 1 Allow the weight to be set on the weighing machine Implement the `WeigingMachine.InputWeight` property to allow the weight to be get and set: -``` csharp +```csharp var wm = new WeighingMachine(); wm.InputWeight = 60m; @@ -41,7 +44,7 @@ wm.InputWeight = 60m; Add validation to the `WeighingMachine.InputWeight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight: -``` csharp +```csharp var wm = new WeighingMachine(); wm.InputWeight = -10m; // Throws an ArgumentException ``` @@ -50,7 +53,7 @@ wm.InputWeight = -10m; // Throws an ArgumentException Implement the `WeighingMachine.USDisplayWeight` property and the `USWeight` class: -``` csharp +```csharp var wm = new WeighingMachine(); wm.InputWeight = 60m; @@ -62,7 +65,7 @@ var usw = wm.USDisplayWeight; Implement the `WeighingMachine.Units` property: -``` csharp +```csharp var wm = new WeighingMachine(); wm.InputWeight = 175.5m; wm.Units = Units.Pounds; @@ -75,7 +78,7 @@ var usw = wm.USDisplayWeight; Implement the `WeighingMachine.TareAdjustment` and `WeighingMachine.DisplayWeight` properties: -``` csharp +```csharp var wm = new WeighingMachine(); wm.InputWeight = 100m; wm.TareAdjustment = 10m; diff --git a/exercises/concept/properties/.docs/introduction.md b/exercises/concept/properties/.docs/introduction.md index 76769a9f35..e2d8f452fc 100644 --- a/exercises/concept/properties/.docs/introduction.md +++ b/exercises/concept/properties/.docs/introduction.md @@ -1,13 +1,13 @@ A property in C# is a member of a class that provides access to data within that class. -Callers can set or retrieve (get) the data. Properties can be either auto-implemented or -have a backing field. They comprise a set accessor and/or a get accessor. +Callers can set or retrieve (get) the data. Properties can be either auto-implemented or +have a backing field. They comprise a set accessor and/or a get accessor. In some other languages a "mutator" is roughly equivalent to a -a set accessor and an "accessor" is roughly equivalent to a set accessor although +a set accessor and an "accessor" is roughly equivalent to a set accessor although the composition of the syntax is completely different. When setting a property the input value can be validated, formatted or otherwise manipulated and in fact any programmatic operation accessible to code in the -class can be executed. +class can be executed. Similarly when retrieving a property data can be calculated or formatted and again any programmatic operation available to the class can be executed. @@ -19,7 +19,8 @@ accessor and vice versa. A property doesn't have to have both accessors, it can The basic syntax to express properties can take two forms: ###### Field/Expression Backed Properties: -``` csharp + +```csharp private int myField; public int MyProperty { @@ -27,8 +28,11 @@ public int MyProperty set { myField = value; } } ``` + ###### Auto-implemented Properties + ``` public int MyProperty { get; private set; } = 42; ``` + Initialisation is optional. diff --git a/reference/exercise-concepts/gigasecond.md b/reference/exercise-concepts/gigasecond.md index bbfe4cefd6..0956d82318 100644 --- a/reference/exercise-concepts/gigasecond.md +++ b/reference/exercise-concepts/gigasecond.md @@ -5,7 +5,7 @@ ## General - functions: used as the main entry point for the exercise -- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. - function arguments: input 'moment' is passed as an arguments - return values: returning a value from a method - scoping: use `{` and `}` to denote scoping diff --git a/reference/exercise-concepts/high-scores.md b/reference/exercise-concepts/high-scores.md index 07eeffd345..6f0c6fb9d6 100644 --- a/reference/exercise-concepts/high-scores.md +++ b/reference/exercise-concepts/high-scores.md @@ -1,17 +1,20 @@ # Concepts of high-scores ## Example implementations + - [Using Generic Collections and LINQ](https://exercism.io/tracks/csharp/exercises/high-scores/solutions/aa676c4a13344a5a9c7b7b944b5f3ad6) - [Using Generic Collections, Sorted list, and Enumeration loops](https://exercism.io/tracks/csharp/exercises/high-scores/solutions/9f55365ea2bb4bf7b70e038002b54a9e) ## Object-oriented -- Classes: used on the template. + +- Classes: used on the template. - Encapsulation: used on the template. There are public elements, some people create private elements (especially when non-LINQ approach is used). - Methods: used on the template; all tested methods needs to be implemented - - methods arguments: constructor receives collection as argument - - return values: returning values from different methods + - methods arguments: constructor receives collection as argument + - return values: returning values from different methods ## Functional + - Pipelines (LINQ): some solutions use that to process the integer collections. - Immutability: some people create readonly pre computed collections. - Anonymous methods: necessary when using LINQ. @@ -21,6 +24,7 @@ - Enumerables: lists can can be iterated over as an enumerable (using LINQ approach) ## General + - Generics: use generic collections (lists). - Enumeration: to process all chars on the string. - Namespaces: used on the template. @@ -30,13 +34,15 @@ - Visibility: making tested method and tested class `public` - Assignment: assigning values - Type inference: using `var` to define complex types -- Numbers: signed integers `int` -- Lists: strongly typed lists of `int` objects +- Numbers: signed integers `int` +- Lists: strongly typed lists of `int` objects ## Approach: Using LINQ + - Enumerable methods for Mapping, Selecting, Ordering: using methods to manipulate enumerables (`LastOrDefault`, `OrderByDescending`, `Take`, `ToList`, `Min`, `Max`) when using LINQ ## Approach: Using sorted lists + - Enumeration loops (for, foreach): iterate over scores using `for`, `foreach` loops - Ordering operators:`<`,`<=` - Math operators: `+`, `+=` within enumeration loops diff --git a/reference/exercise-concepts/protein-translation.md b/reference/exercise-concepts/protein-translation.md index 2fe70e200e..09f0b05750 100644 --- a/reference/exercise-concepts/protein-translation.md +++ b/reference/exercise-concepts/protein-translation.md @@ -16,7 +16,7 @@ - lists: a `List` temporarily holds the results before converting them to an array (Add and ToArray methods) - for loop: iterate through the strands - integers: `int` type used as a counter in the loop -- math operations: <, *, and ++ +- math operations: <, \*, and ++ - strings: substring and comparison - exceptions: throw an exception in the event of invalid input diff --git a/reference/exercise-concepts/resistor-color.md b/reference/exercise-concepts/resistor-color.md index 61a670de55..2ce0825e7d 100644 --- a/reference/exercise-concepts/resistor-color.md +++ b/reference/exercise-concepts/resistor-color.md @@ -5,7 +5,7 @@ ## General - functions: used as the main entry point for the exercise -- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. +- static function: the static keyword is the modifier that makes the method static, and enables it to be called without instantiation. The static method can access the variables passed in as arguments, global, and only other static members of the class. - function arguments: input color is passed as an arguments - return values: returning a value from a method - exceptions: throw an exception in the event of invalid/null input @@ -17,7 +17,7 @@ - namespaces: knowing where to find the `Array` class - expression body method: it makes the code cleaner for a short (one-line) method - immutability: defining the colors in an array as `readonly` -- string: array elements defined as string +- string: array elements defined as string - array: creating an array to hold list of colors - static method: to access metods at the type level. - int: return sign integers From c0ea68b6a97d39ba4ef44cf9592637e91101f51c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 17 Apr 2020 14:58:56 +0200 Subject: [PATCH 103/327] Normalize code * Normalize examples * Normalize tests Co-authored-by: wolf99 <281700+wolf99@users.noreply.github.com> --- exercises/concept/basics/.meta/Example.cs | 23 ++-- exercises/concept/basics/BasicsTests.cs | 24 +++-- exercises/concept/datetimes/.meta/Example.cs | 30 ++++-- exercises/concept/datetimes/DateTimesTests.cs | 100 +++++++++++++----- exercises/concept/enums/.meta/Example.cs | 47 ++++---- exercises/concept/enums/EnumsTests.cs | 60 ++++++++--- exercises/concept/flag-enums/.meta/Example.cs | 38 ++++--- .../concept/flag-enums/FlagEnumsTests.cs | 88 +++++++++++---- .../floating-point-numbers/.meta/Example.cs | 12 ++- .../FloatingPointNumbersTests.cs | 96 ++++++++++++----- exercises/concept/numbers/.meta/Example.cs | 24 +++-- exercises/concept/numbers/NumbersTests.cs | 48 ++++++--- exercises/concept/properties/.meta/Example.cs | 12 ++- exercises/concept/strings/.meta/Example.cs | 18 ++-- exercises/concept/strings/StringsTests.cs | 44 ++++++-- 15 files changed, 479 insertions(+), 185 deletions(-) diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/basics/.meta/Example.cs index 8213a773c3..1fadf5b279 100644 --- a/exercises/concept/basics/.meta/Example.cs +++ b/exercises/concept/basics/.meta/Example.cs @@ -1,13 +1,22 @@ public class Lasagna { - public int ExpectedMinutesInOven() => 40; + public int ExpectedMinutesInOven() + { + return 40; + } - public int RemainingMinutesInOven(int actualMinutesInOven) => - ExpectedMinutesInOven() - actualMinutesInOven; + public int RemainingMinutesInOven(int actualMinutesInOven) + { + return ExpectedMinutesInOven() - actualMinutesInOven; + } - public int PreparationTimeInMinutes(int numberOfLayers) => - numberOfLayers * 2; + public int PreparationTimeInMinutes(int numberOfLayers) + { + return numberOfLayers * 2; + } - public int TotalTimeInMinutes(int numberOfLayers, int actualMinutesInOven) => - PreparationTimeInMinutes(numberOfLayers) + actualMinutesInOven; + public int TotalTimeInMinutes(int numberOfLayers, int actualMinutesInOven) + { + return PreparationTimeInMinutes(numberOfLayers) + actualMinutesInOven; + } } \ No newline at end of file diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs index 7441d3b5d5..47e0a2d023 100644 --- a/exercises/concept/basics/BasicsTests.cs +++ b/exercises/concept/basics/BasicsTests.cs @@ -3,26 +3,38 @@ public class LasagnaTests { [Fact] - public void ExpectedMinutesInOven() => + public void ExpectedMinutesInOven() + { Assert.Equal(40, new Lasagna().ExpectedMinutesInOven()); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RemainingMinutesInOven() => + public void RemainingMinutesInOven() + { Assert.Equal(15, new Lasagna().RemainingMinutesInOven(25)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void PreparationTimeInMinutesForOneLayer() => + public void PreparationTimeInMinutesForOneLayer() + { Assert.Equal(2, new Lasagna().PreparationTimeInMinutes(1)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void PreparationTimeInMinutesForMultipleLayers() => + public void PreparationTimeInMinutesForMultipleLayers() + { Assert.Equal(8, new Lasagna().PreparationTimeInMinutes(4)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void TotalTimeInMinutesForOneLayer() => + public void TotalTimeInMinutesForOneLayer() + { Assert.Equal(32, new Lasagna().TotalTimeInMinutes(1, 30)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void TotalTimeInMinutesForMultipleLayers() => + public void TotalTimeInMinutesForMultipleLayers() + { Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); + } } \ No newline at end of file diff --git a/exercises/concept/datetimes/.meta/Example.cs b/exercises/concept/datetimes/.meta/Example.cs index 0db32e60af..0db866544a 100644 --- a/exercises/concept/datetimes/.meta/Example.cs +++ b/exercises/concept/datetimes/.meta/Example.cs @@ -2,18 +2,28 @@ public static class Appointment { - public static DateTime Schedule(string appointmentDateDescription) => - DateTime.Parse(appointmentDateDescription); + public static DateTime Schedule(string appointmentDateDescription) + { + return DateTime.Parse(appointmentDateDescription); + } - public static bool HasPassed(DateTime appointmentDate) => - appointmentDate < DateTime.Now; + public static bool HasPassed(DateTime appointmentDate) + { + return appointmentDate < DateTime.Now; + } - public static bool IsAfternoonAppointment(DateTime appointmentDate) => - appointmentDate.Hour >= 12 && appointmentDate.Hour < 18; + public static bool IsAfternoonAppointment(DateTime appointmentDate) + { + return appointmentDate.Hour >= 12 && appointmentDate.Hour < 18; + } - public static string Description(DateTime appointmentDate) => - $"You have an appointment on {appointmentDate}."; + public static string Description(DateTime appointmentDate) + { + return $"You have an appointment on {appointmentDate}."; + } - public static DateTime AnniversaryDate() => - new DateTime(DateTime.Now.Year, 9, 15); + public static DateTime AnniversaryDate() + { + return new DateTime(DateTime.Now.Year, 9, 15); + } } \ No newline at end of file diff --git a/exercises/concept/datetimes/DateTimesTests.cs b/exercises/concept/datetimes/DateTimesTests.cs index ea58e5d0fd..d8e96a51db 100644 --- a/exercises/concept/datetimes/DateTimesTests.cs +++ b/exercises/concept/datetimes/DateTimesTests.cs @@ -9,104 +9,154 @@ public class AppointmentTests { [Fact] - public void ScheduleDateUsingOnlyNumbers() => + public void ScheduleDateUsingOnlyNumbers() + { Assert.Equal(new DateTime(2019, 07, 25, 13, 45, 0), Appointment.Schedule("7/25/2019 13:45:00")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ScheduleDateWithTextualMonth() => + public void ScheduleDateWithTextualMonth() + { Assert.Equal(new DateTime(2019, 6, 3, 11, 30, 0), Appointment.Schedule("June 3, 2019 11:30:00")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ScheduleDateWithTextualMonthAndWeekday() => + public void ScheduleDateWithTextualMonthAndWeekday() + { Assert.Equal(new DateTime(2019, 12, 5, 9, 0, 0), Appointment.Schedule("Thursday, December 5, 2019 09:00:00")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentOneYearAgo() => + public void HasPassedWithAppointmentOneYearAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentMonthsAgo() => + public void HasPassedWithAppointmentMonthsAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddMonths(-8))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentDaysAgo() => + public void HasPassedWithAppointmentDaysAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddDays(-23))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentHoursAgo() => + public void HasPassedWithAppointmentHoursAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddHours(-12))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentMinutesAgo() => + public void HasPassedWithAppointmentMinutesAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-55))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentOneMinuteAgo() => + public void HasPassedWithAppointmentOneMinuteAgo() + { Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-1))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInOneMinute() => + public void HasPassedWithAppointmentInOneMinute() + { Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(1))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInMinutes() => + public void HasPassedWithAppointmentInMinutes() + { Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(5))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInDays() => + public void HasPassedWithAppointmentInDays() + { Assert.False(Appointment.HasPassed(DateTime.Now.AddDays(19))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInMonths() => + public void HasPassedWithAppointmentInMonths() + { Assert.False(Appointment.HasPassed(DateTime.Now.AddMonths(10))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInYears() => + public void HasPassedWithAppointmentInYears() + { Assert.False(Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyMorningAppointment() => + public void IsAfternoonAppointmentForEarlyMorningAppointment() + { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateMorningAppointment() => + public void IsAfternoonAppointmentForLateMorningAppointment() + { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForNoonAppointment() => + public void IsAfternoonAppointmentForNoonAppointment() + { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyAfternoonAppointment() => + public void IsAfternoonAppointmentForEarlyAfternoonAppointment() + { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateAfternoonAppointment() => + public void IsAfternoonAppointmentForLateAfternoonAppointment() + { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyEveningAppointment() => + public void IsAfternoonAppointmentForEarlyEveningAppointment() + { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateEveningAppointment() => + public void IsAfternoonAppointmentForLateEveningAppointment() + { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnFridayAfternoon() => + public void DescriptionOnFridayAfternoon() + { Assert.Equal("You have an appointment on 3/29/2019 3:00:00 PM.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnThursdayAfternoon() => + public void DescriptionOnThursdayAfternoon() + { Assert.Equal("You have an appointment on 7/25/2019 1:45:00 PM.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnWednesdayMorning() => + public void DescriptionOnWednesdayMorning() + { Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); + } [Fact] - public void AnniversaryDate() => + public void AnniversaryDate() + { Assert.Equal(new DateTime(DateTime.Now.Year, 9, 15), Appointment.AnniversaryDate()); + } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] private class UseCultureAttribute : BeforeAfterTestAttribute diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/enums/.meta/Example.cs index 12189112a4..e191810243 100644 --- a/exercises/concept/enums/.meta/Example.cs +++ b/exercises/concept/enums/.meta/Example.cs @@ -1,5 +1,3 @@ -using System; - public enum LogLevel { Trace = 0, @@ -13,26 +11,29 @@ public enum LogLevel public static class LogLine { - public static LogLevel ParseLogLevel(string logLine) { - - switch (logLine.Substring(1, 3)) { - case "TRC": - return LogLevel.Trace; - case "DBG": - return LogLevel.Debug; - case "INF": - return LogLevel.Info; - case "WRN": - return LogLevel.Warning; - case "ERR": - return LogLevel.Error; - case "FTL": - return LogLevel.Fatal; - default: - return LogLevel.Unknown; - } - } + public static LogLevel ParseLogLevel(string logLine) + { + switch (logLine.Substring(1, 3)) + { + case "TRC": + return LogLevel.Trace; + case "DBG": + return LogLevel.Debug; + case "INF": + return LogLevel.Info; + case "WRN": + return LogLevel.Warning; + case "ERR": + return LogLevel.Error; + case "FTL": + return LogLevel.Fatal; + default: + return LogLevel.Unknown; + } + } - public static string OutputForShortLog(LogLevel logLevel, string message) => - $"{(int)logLevel}:{message}"; + public static string OutputForShortLog(LogLevel logLevel, string message) + { + return $"{(int)logLevel}:{message}"; + } } diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/enums/EnumsTests.cs index 928cde434c..d982873fe0 100644 --- a/exercises/concept/enums/EnumsTests.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -3,58 +3,86 @@ public class LogLineTests { [Fact] - public void ParseTrace() => + public void ParseTrace() + { Assert.Equal(LogLevel.Trace, LogLine.ParseLogLevel("[TRC]: Line 84 - Console.WriteLine('Hello World');")); - + } + [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseDebug() => + public void ParseDebug() + { Assert.Equal(LogLevel.Debug, LogLine.ParseLogLevel("[DBG]: ; expected")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseInfo() => + public void ParseInfo() + { Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INF]: Timezone changed")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseWarning() => + public void ParseWarning() + { Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WRN]: Timezone not set")); - + } + [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseError() => + public void ParseError() + { Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERR]: Disk full")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseFatal() => + public void ParseFatal() + { Assert.Equal(LogLevel.Fatal, LogLine.ParseLogLevel("[FTL]: Not enough memory")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseUnknown() => + public void ParseUnknown() + { Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[XYZ]: Gibberish message.. beep boop..")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForTrace() => + public void OutputForShortLogForTrace() + { Assert.Equal("0:Line 13 - int myNum = 42;", LogLine.OutputForShortLog(LogLevel.Trace, "Line 13 - int myNum = 42;")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForDebug() => + public void OutputForShortLogForDebug() + { Assert.Equal("1:The name 'LogLevel' does not exist in the current context", LogLine.OutputForShortLog(LogLevel.Debug, "The name 'LogLevel' does not exist in the current context")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForInfo() => + public void OutputForShortLogForInfo() + { Assert.Equal("4:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForWarning() => + public void OutputForShortLogForWarning() + { Assert.Equal("5:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForError() => + public void OutputForShortLogForError() + { Assert.Equal("6:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForFatal() => + public void OutputForShortLogForFatal() + { Assert.Equal("7:Dumping all files", LogLine.OutputForShortLog(LogLevel.Fatal, "Dumping all files")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForUnknown() => + public void OutputForShortLogForUnknown() + { Assert.Equal("42:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); + } } diff --git a/exercises/concept/flag-enums/.meta/Example.cs b/exercises/concept/flag-enums/.meta/Example.cs index bd3cda627f..1cf226034c 100644 --- a/exercises/concept/flag-enums/.meta/Example.cs +++ b/exercises/concept/flag-enums/.meta/Example.cs @@ -19,21 +19,33 @@ public enum Permission public static class Permissions { - public static Permission Default(AccountType accountType) => - accountType switch + public static Permission Default(AccountType accountType) + { + switch (accountType) { - AccountType.Guest => Permission.Read, - AccountType.User => Permission.Read | Permission.Write, - AccountType.Moderator => Permission.Read | Permission.Write | Permission.Delete, - _ => Permission.None - }; + case AccountType.Guest: + return Permission.Read; + case AccountType.User: + return Permission.Read | Permission.Write; + case AccountType.Moderator: + return Permission.Read | Permission.Write | Permission.Delete; + default: + return Permission.None; + } + } - public static Permission Grant(Permission current, Permission grant) => - current | grant; + public static Permission Grant(Permission current, Permission grant) + { + return current | grant; + } - public static Permission Revoke(Permission current, Permission revoke) => - current & ~revoke; + public static Permission Revoke(Permission current, Permission revoke) + { + return current & ~revoke; + } - public static bool Check(Permission current, Permission check) => - current.HasFlag(check); + public static bool Check(Permission current, Permission check) + { + return current.HasFlag(check); + } } \ No newline at end of file diff --git a/exercises/concept/flag-enums/FlagEnumsTests.cs b/exercises/concept/flag-enums/FlagEnumsTests.cs index 6067964614..50d84c98cb 100644 --- a/exercises/concept/flag-enums/FlagEnumsTests.cs +++ b/exercises/concept/flag-enums/FlagEnumsTests.cs @@ -3,90 +3,134 @@ public class PermissionsTests { [Fact] - public void DefaultForGuest() => + public void DefaultForGuest() + { Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForUser() => + public void DefaultForUser() + { Assert.Equal(Permission.Read | Permission.Write, Permissions.Default(AccountType.User)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForModerator() => + public void DefaultForModerator() + { Assert.Equal(Permission.Read | Permission.Write | Permission.Delete, Permissions.Default(AccountType.Moderator)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForUnknown() => + public void DefaultForUnknown() + { Assert.Equal(Permission.None, Permissions.Default((AccountType)123)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadToNone() => + public void GrantReadToNone() + { Assert.Equal(Permission.Read, Permissions.Grant(Permission.None, Permission.Read)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadToRead() => + public void GrantReadToRead() + { Assert.Equal(Permission.Read, Permissions.Grant(Permission.Read, Permission.Read)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantAllToNone() => + public void GrantAllToNone() + { Assert.Equal(Permission.All, Permissions.Grant(Permission.None, Permission.All)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantDeleteToReadAndWrite() => + public void GrantDeleteToReadAndWrite() + { Assert.Equal(Permission.All, Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadAndWriteToNone() => + public void GrantReadAndWriteToNone() + { Assert.Equal(Permission.Read | Permission.Write, Permissions.Grant(Permission.None, Permission.Read | Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeNoneFromRead() => + public void RevokeNoneFromRead() + { Assert.Equal(Permission.Read, Permissions.Revoke(Permission.Read, Permission.None)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeWriteFromWrite() => + public void RevokeWriteFromWrite() + { Assert.Equal(Permission.None, Permissions.Revoke(Permission.Write, Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeDeleteFromAll() => + public void RevokeDeleteFromAll() + { Assert.Equal(Permission.Read | Permission.Write, Permissions.Revoke(Permission.All, Permission.Delete)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeReadAndWriteFromWriteAndDelete() => + public void RevokeReadAndWriteFromWriteAndDelete() + { Assert.Equal(Permission.Delete, Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeAllFromReadAndWrite() => + public void RevokeAllFromReadAndWrite() + { Assert.Equal(Permission.None, Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckNoneForRead() => + public void CheckNoneForRead() + { Assert.False(Permissions.Check(Permission.None, Permission.Read)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckWriteForWrite() => + public void CheckWriteForWrite() + { Assert.True(Permissions.Check(Permission.Write, Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckAllForWrite() => + public void CheckAllForWrite() + { Assert.True(Permissions.Check(Permission.All, Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForRead() => + public void CheckReadAndWriteForRead() + { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckAllForReadAndWrite() => + public void CheckAllForReadAndWrite() + { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForReadAndWrite() => + public void CheckReadAndWriteForReadAndWrite() + { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForReadAndDelete() => + public void CheckReadAndWriteForReadAndDelete() + { Assert.False(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteAndDeleteForAll() => + public void CheckReadAndWriteAndDeleteForAll() + { Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); + } } \ No newline at end of file diff --git a/exercises/concept/floating-point-numbers/.meta/Example.cs b/exercises/concept/floating-point-numbers/.meta/Example.cs index 49acf77217..d856b7a939 100644 --- a/exercises/concept/floating-point-numbers/.meta/Example.cs +++ b/exercises/concept/floating-point-numbers/.meta/Example.cs @@ -5,13 +5,19 @@ public static class SavingsAccount public static float InterestRate(decimal balance) { if (balance < 0.0m) + { return -3.213f; + } if (balance < 1000.0m) + { return 0.5f; + } if (balance < 5000.0m) + { return 1.621f; + } return 2.475f; } @@ -22,8 +28,10 @@ private static decimal AnnualYield(decimal balance) return Math.Abs(balance) * multiplier; } - public static decimal AnnualBalanceUpdate(decimal balance) => - balance + AnnualYield(balance); + public static decimal AnnualBalanceUpdate(decimal balance) + { + return balance + AnnualYield(balance); + } public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalance) { diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs index 7dbc394739..eac6d19007 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs @@ -3,98 +3,146 @@ public class SavingsAccountTests { [Fact] - public void MinimalFirstInterestRate() => + public void MinimalFirstInterestRate() + { Assert.Equal(0.5f, SavingsAccount.InterestRate(0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinyFirstInterestRate() => + public void TinyFirstInterestRate() + { Assert.Equal(0.5f, SavingsAccount.InterestRate(0.000001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MaximumFirstInterestRate() => + public void MaximumFirstInterestRate() + { Assert.Equal(0.5f, SavingsAccount.InterestRate(999.9999m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalSecondInterestRate() => + public void MinimalSecondInterestRate() + { Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinySecondInterestRate() => + public void TinySecondInterestRate() + { Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MaximumSecondInterestRate() => + public void MaximumSecondInterestRate() + { Assert.Equal(1.621f, SavingsAccount.InterestRate(4_999.9990m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalThirdInterestRate() => + public void MinimalThirdInterestRate() + { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0000m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinyThirdInterestRate() => + public void TinyThirdInterestRate() + { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void LargeThirdInterestRate() => + public void LargeThirdInterestRate() + { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_639_998.742909m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalNegativeInterestRate() => + public void MinimalNegativeInterestRate() + { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.000001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void SmallNegativeInterestRate() => + public void SmallNegativeInterestRate() + { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.123m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void RegularNegativeInterestRate() => + public void RegularNegativeInterestRate() + { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-300.0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void LargeNegativeInterestRate() => + public void LargeNegativeInterestRate() + { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-152964.231m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForEmptyStartBalance() => + public void AnnualBalanceUpdateForEmptyStartBalance() + { Assert.Equal(0.0000m, SavingsAccount.AnnualBalanceUpdate(0.0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForSmallPositiveStartBalance() => + public void AnnualBalanceUpdateForSmallPositiveStartBalance() + { Assert.Equal(0.000001005m, SavingsAccount.AnnualBalanceUpdate(0.000001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForAveragePositiveStartBalance() => + public void AnnualBalanceUpdateForAveragePositiveStartBalance() + { Assert.Equal(1016.210000m, SavingsAccount.AnnualBalanceUpdate(1_000.0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForLargePositiveStartBalance() => + public void AnnualBalanceUpdateForLargePositiveStartBalance() + { Assert.Equal(1016.210101621m, SavingsAccount.AnnualBalanceUpdate(1_000.0001m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForHugePositiveStartBalance() => + public void AnnualBalanceUpdateForHugePositiveStartBalance() + { Assert.Equal(920352587.26744292868451875m, SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForSmallNegativeStartBalance() => + public void AnnualBalanceUpdateForSmallNegativeStartBalance() + { Assert.Equal(-0.12695199m, SavingsAccount.AnnualBalanceUpdate(-0.123m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForLargeNegativeStartBalance() => + public void AnnualBalanceUpdateForLargeNegativeStartBalance() + { Assert.Equal(-157878.97174203m, SavingsAccount.AnnualBalanceUpdate(-152964.231m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForSmallStartBalance() => + public void YearsBeforeDesiredBalanceForSmallStartBalance() + { Assert.Equal(47, SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForAverageStartBalance() => + public void YearsBeforeDesiredBalanceForAverageStartBalance() + { Assert.Equal(6, SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForLargeStartBalance() => + public void YearsBeforeDesiredBalanceForLargeStartBalance() + { Assert.Equal(5, SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() => + public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() + { Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); + } } \ No newline at end of file diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index 10ce8a42b1..5476ec0da1 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -2,25 +2,37 @@ public static class AssemblyLine { private const int ProductionRatePerHourForDefaultSpeed = 221; - public static double ProductionRatePerHour(int speed) => - ProductionRatePerHourForSpeed(speed) * SuccessRate(speed); + public static double ProductionRatePerHour(int speed) + { + return ProductionRatePerHourForSpeed(speed) * SuccessRate(speed); + } - private static int ProductionRatePerHourForSpeed(int speed) => - ProductionRatePerHourForDefaultSpeed * speed; + private static int ProductionRatePerHourForSpeed(int speed) + { + return ProductionRatePerHourForDefaultSpeed * speed; + } - public static int WorkingItemsPerMinute(int speed) => - (int)(ProductionRatePerHour(speed) / 60); + public static int WorkingItemsPerMinute(int speed) + { + return (int)(ProductionRatePerHour(speed) / 60); + } private static double SuccessRate(int speed) { if (speed == 10) + { return 0.77; + } if (speed == 9) + { return 0.8; + } if (speed >= 5) + { return 0.9; + } return 1; } diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/numbers/NumbersTests.cs index c089dd8f4f..d8aad5b748 100644 --- a/exercises/concept/numbers/NumbersTests.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -3,50 +3,74 @@ public class AssemblyLineTests { [Fact] - public void ProductionRatePerHourForSpeedZero() => + public void ProductionRatePerHourForSpeedZero() + { Assert.Equal(0.0, AssemblyLine.ProductionRatePerHour(0)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedOne() => + public void ProductionRatePerHourForSpeedOne() + { Assert.Equal(221.0, AssemblyLine.ProductionRatePerHour(1)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedFour() => + public void ProductionRatePerHourForSpeedFour() + { Assert.Equal(884.0, AssemblyLine.ProductionRatePerHour(4)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedSeven() => + public void ProductionRatePerHourForSpeedSeven() + { Assert.Equal(1392.3, AssemblyLine.ProductionRatePerHour(7)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedNine() => + public void ProductionRatePerHourForSpeedNine() + { Assert.Equal(1591.2, AssemblyLine.ProductionRatePerHour(9)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedTen() => + public void ProductionRatePerHourForSpeedTen() + { Assert.Equal(1701.7, AssemblyLine.ProductionRatePerHour(10)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedZero() => + public void WorkingItemsPerMinuteForSpeedZero() + { Assert.Equal(0, AssemblyLine.WorkingItemsPerMinute(0)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedOne() => + public void WorkingItemsPerMinuteForSpeedOne() + { Assert.Equal(3, AssemblyLine.WorkingItemsPerMinute(1)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedFive() => + public void WorkingItemsPerMinuteForSpeedFive() + { Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedEight() => + public void WorkingItemsPerMinuteForSpeedEight() + { Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedNine() => + public void WorkingItemsPerMinuteForSpeedNine() + { Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(9)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedTen() => + public void WorkingItemsPerMinuteForSpeedTen() + { Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); + } } diff --git a/exercises/concept/properties/.meta/Example.cs b/exercises/concept/properties/.meta/Example.cs index 3023f6f48c..0b78e3a447 100644 --- a/exercises/concept/properties/.meta/Example.cs +++ b/exercises/concept/properties/.meta/Example.cs @@ -5,15 +5,20 @@ public enum Units Pounds, Kilograms } + public class WeighingMachine { private const decimal POUNDS_PER_KILOGRAM = 2.20462m; private decimal inputWeight; public Units Units { get; set; } = Units.Kilograms; + public decimal InputWeight { - get { return inputWeight; } + get + { + return inputWeight; + } set { if (value < 0) @@ -27,7 +32,10 @@ public decimal InputWeight public decimal DisplayWeight { - get { return ApplyTareAdjustment(inputWeight); } + get + { + return ApplyTareAdjustment(inputWeight); + } } public USWeight USDisplayWeight { diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs index faf1a56bf4..d26891b58b 100644 --- a/exercises/concept/strings/.meta/Example.cs +++ b/exercises/concept/strings/.meta/Example.cs @@ -1,11 +1,17 @@ public static class LogLine { - public static string Message(string logLine) => - logLine.Substring(logLine.IndexOf(":") + 1).Trim(); + public static string Message(string logLine) + { + return logLine.Substring(logLine.IndexOf(":") + 1).Trim(); + } - public static string LogLevel(string logLine) => - logLine.Substring(1, logLine.IndexOf("]")).ToLower(); + public static string LogLevel(string logLine) + { + return logLine.Substring(1, logLine.IndexOf("]")).ToLower(); + } - public static string Reformat(string logLine) => - $"{Message(logLine)} ({LogLevel(logLine)})"; + public static string Reformat(string logLine) + { + return $"{Message(logLine)} ({LogLevel(logLine)})"; + } } \ No newline at end of file diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/strings/StringsTests.cs index 85f4aee7a9..ac03a43567 100644 --- a/exercises/concept/strings/StringsTests.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -3,46 +3,68 @@ public class LogLineTests { [Fact] - public void ErrorMessage() => + public void ErrorMessage() + { Assert.Equal("Stack overflow", LogLine.Message("[ERROR]: Stack overflow")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningMessage() => + public void WarningMessage() + { Assert.Equal("Disk almost full", LogLine.Message("[WARNING]: Disk almost full")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoMessage() => + public void InfoMessage() + { Assert.Equal("File moved", LogLine.Message("[INFO]: File moved")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MessageWithLeadingAndTrailingWhiteSpace() => + public void MessageWithLeadingAndTrailingWhiteSpace() + { Assert.Equal("Timezone not set", LogLine.Message("[WARNING]: \tTimezone not set \r\n")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ErrorLogLevel() => + public void ErrorLogLevel() + { Assert.Equal("error", LogLine.LogLevel("[ERROR]: Disk full")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningLogLevel() => + public void WarningLogLevel() + { Assert.Equal("warning", LogLine.LogLevel("[WARNING]: Unsafe password")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoLogLevel() => + public void InfoLogLevel() + { Assert.Equal("info", LogLine.LogLevel("[INFO]: Timezone changed")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ErrorReformat() => + public void ErrorReformat() + { Assert.Equal("Segmentation fault (error)", LogLine.Reformat("[ERROR]: Segmentation fault")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningReformat() => + public void WarningReformat() + { Assert.Equal("Decreased performance (warning)", LogLine.Reformat("[WARNING]: Decreased performance")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoReformat() => + public void InfoReformat() + { Assert.Equal("Disk defragmented (info)", LogLine.Reformat("[INFO]: Disk defragmented")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void ReformatWithLeadingAndTrailingWhiteSpace() => + public void ReformatWithLeadingAndTrailingWhiteSpace() + { Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); + } } \ No newline at end of file From 7927105d80be0fc21bd74038a732d5e8f6af9361 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 17 Apr 2020 15:47:49 +0200 Subject: [PATCH 104/327] Allow code to be formatted automatically Add script to format code --- exercises/concept/basics/.meta/Example.cs | 2 +- exercises/concept/basics/Basics.cs | 2 +- exercises/concept/basics/BasicsTests.cs | 2 +- exercises/concept/datetimes/.meta/Example.cs | 2 +- exercises/concept/datetimes/DateTimes.cs | 2 +- exercises/concept/datetimes/DateTimesTests.cs | 2 +- exercises/concept/flag-enums/.meta/Example.cs | 2 +- exercises/concept/flag-enums/FlagEnums.cs | 2 +- exercises/concept/flag-enums/FlagEnumsTests.cs | 2 +- exercises/concept/floating-point-numbers/.meta/Example.cs | 2 +- .../floating-point-numbers/FloatingPointNumbers.cs | 2 +- .../floating-point-numbers/FloatingPointNumbersTests.cs | 2 +- exercises/concept/numbers/.meta/Example.cs | 2 +- exercises/concept/numbers/Numbers.cs | 2 +- exercises/concept/properties/Properties.cs | 6 +++--- exercises/concept/properties/PropertiesTests.cs | 2 +- exercises/concept/strings/.meta/Example.cs | 2 +- exercises/concept/strings/Strings.cs | 2 +- exercises/concept/strings/StringsTests.cs | 2 +- reference/implementing-a-concept-exercise.md | 8 ++++++++ 20 files changed, 29 insertions(+), 21 deletions(-) diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/basics/.meta/Example.cs index 1fadf5b279..7617e1537d 100644 --- a/exercises/concept/basics/.meta/Example.cs +++ b/exercises/concept/basics/.meta/Example.cs @@ -19,4 +19,4 @@ public int TotalTimeInMinutes(int numberOfLayers, int actualMinutesInOven) { return PreparationTimeInMinutes(numberOfLayers) + actualMinutesInOven; } -} \ No newline at end of file +} diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/basics/Basics.cs index 767eef4df4..f3b8b3bb01 100644 --- a/exercises/concept/basics/Basics.cs +++ b/exercises/concept/basics/Basics.cs @@ -7,4 +7,4 @@ public class Lasagna // TODO: define the 'PreparationTimeInMinutes' method // TODO: define the 'TotalTimeInMinutes' method -} \ No newline at end of file +} diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs index 47e0a2d023..1feccb141c 100644 --- a/exercises/concept/basics/BasicsTests.cs +++ b/exercises/concept/basics/BasicsTests.cs @@ -37,4 +37,4 @@ public void TotalTimeInMinutesForMultipleLayers() { Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); } -} \ No newline at end of file +} diff --git a/exercises/concept/datetimes/.meta/Example.cs b/exercises/concept/datetimes/.meta/Example.cs index 0db866544a..65f4a821a6 100644 --- a/exercises/concept/datetimes/.meta/Example.cs +++ b/exercises/concept/datetimes/.meta/Example.cs @@ -26,4 +26,4 @@ public static DateTime AnniversaryDate() { return new DateTime(DateTime.Now.Year, 9, 15); } -} \ No newline at end of file +} diff --git a/exercises/concept/datetimes/DateTimes.cs b/exercises/concept/datetimes/DateTimes.cs index 208242dd26..9b99d43e1a 100644 --- a/exercises/concept/datetimes/DateTimes.cs +++ b/exercises/concept/datetimes/DateTimes.cs @@ -26,4 +26,4 @@ public static DateTime AnniversaryDate() { throw new NotImplementedException("Please implement the Appointment.AnniversaryDate method"); } -} \ No newline at end of file +} diff --git a/exercises/concept/datetimes/DateTimesTests.cs b/exercises/concept/datetimes/DateTimesTests.cs index d8e96a51db..8a0adf672d 100644 --- a/exercises/concept/datetimes/DateTimesTests.cs +++ b/exercises/concept/datetimes/DateTimesTests.cs @@ -196,4 +196,4 @@ public override void After(MethodInfo methodUnderTest) CultureInfo.CurrentUICulture.ClearCachedData(); } } -} \ No newline at end of file +} diff --git a/exercises/concept/flag-enums/.meta/Example.cs b/exercises/concept/flag-enums/.meta/Example.cs index 1cf226034c..720e8a460e 100644 --- a/exercises/concept/flag-enums/.meta/Example.cs +++ b/exercises/concept/flag-enums/.meta/Example.cs @@ -48,4 +48,4 @@ public static bool Check(Permission current, Permission check) { return current.HasFlag(check); } -} \ No newline at end of file +} diff --git a/exercises/concept/flag-enums/FlagEnums.cs b/exercises/concept/flag-enums/FlagEnums.cs index 36ae239a1c..f9a8599092 100644 --- a/exercises/concept/flag-enums/FlagEnums.cs +++ b/exercises/concept/flag-enums/FlagEnums.cs @@ -25,4 +25,4 @@ public static bool Check(Permission current, Permission check) { throw new NotImplementedException("Please implement the Permissions.Check method"); } -} \ No newline at end of file +} diff --git a/exercises/concept/flag-enums/FlagEnumsTests.cs b/exercises/concept/flag-enums/FlagEnumsTests.cs index 50d84c98cb..d8f653c9b6 100644 --- a/exercises/concept/flag-enums/FlagEnumsTests.cs +++ b/exercises/concept/flag-enums/FlagEnumsTests.cs @@ -133,4 +133,4 @@ public void CheckReadAndWriteAndDeleteForAll() { Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); } -} \ No newline at end of file +} diff --git a/exercises/concept/floating-point-numbers/.meta/Example.cs b/exercises/concept/floating-point-numbers/.meta/Example.cs index d856b7a939..ea36426d02 100644 --- a/exercises/concept/floating-point-numbers/.meta/Example.cs +++ b/exercises/concept/floating-point-numbers/.meta/Example.cs @@ -46,4 +46,4 @@ public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalan return years; } -} \ No newline at end of file +} diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs index 3b54ef28c3..4247d08644 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs @@ -16,4 +16,4 @@ public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalan { throw new NotImplementedException("Please implement the SavingsAccount.YearsBeforeDesiredBalance method"); } -} \ No newline at end of file +} diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs index eac6d19007..2786f06d0e 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs @@ -145,4 +145,4 @@ public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalan { Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); } -} \ No newline at end of file +} diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index 5476ec0da1..5d9613b8c4 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -36,4 +36,4 @@ private static double SuccessRate(int speed) return 1; } -} \ No newline at end of file +} diff --git a/exercises/concept/numbers/Numbers.cs b/exercises/concept/numbers/Numbers.cs index c888768923..94487e5ae7 100644 --- a/exercises/concept/numbers/Numbers.cs +++ b/exercises/concept/numbers/Numbers.cs @@ -11,4 +11,4 @@ public static int WorkingItemsPerMinute(int speed) { throw new NotImplementedException("Please implement the AssemblyLine.WorkingItemsPerMinute method"); } -} \ No newline at end of file +} diff --git a/exercises/concept/properties/Properties.cs b/exercises/concept/properties/Properties.cs index 6a64e6bbf5..abdaad50fb 100644 --- a/exercises/concept/properties/Properties.cs +++ b/exercises/concept/properties/Properties.cs @@ -13,19 +13,19 @@ public class WeighingMachine // TODO: define the 'DisplayWeight' property // TODO: define the 'USDisplayWeight' property - + // TODO: define the 'TareAdjustment' property // TODO: define the 'Units' property } + public struct USWeight { - public USWeight(decimal weightInPounds) { throw new NotImplementedException("Please implement the USWeight classes' constructor"); } - + // TODO: define the 'Pounds' property // TODO: define the 'Ounces' property diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/properties/PropertiesTests.cs index 0e38a8133b..978ba1e23c 100644 --- a/exercises/concept/properties/PropertiesTests.cs +++ b/exercises/concept/properties/PropertiesTests.cs @@ -17,7 +17,7 @@ public void Negative_weight_is_invalid() var wm = new WeighingMachine(); Assert.Throws(() => wm.InputWeight = -10); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void Get_US_display_weight() { diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs index d26891b58b..626096324d 100644 --- a/exercises/concept/strings/.meta/Example.cs +++ b/exercises/concept/strings/.meta/Example.cs @@ -14,4 +14,4 @@ public static string Reformat(string logLine) { return $"{Message(logLine)} ({LogLevel(logLine)})"; } -} \ No newline at end of file +} diff --git a/exercises/concept/strings/Strings.cs b/exercises/concept/strings/Strings.cs index f1fa861bb0..d141880a0c 100644 --- a/exercises/concept/strings/Strings.cs +++ b/exercises/concept/strings/Strings.cs @@ -16,4 +16,4 @@ public static string Reformat(string logLine) { throw new NotImplementedException("Please implement the LogLine.Reformat method"); } -} \ No newline at end of file +} diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/strings/StringsTests.cs index ac03a43567..91a376001a 100644 --- a/exercises/concept/strings/StringsTests.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -67,4 +67,4 @@ public void ReformatWithLeadingAndTrailingWhiteSpace() { Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); } -} \ No newline at end of file +} diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 6cc4a53b6a..6fab139654 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -67,6 +67,13 @@ Some exercises could benefit from having an custom representation as generated b Skip this step if you're not sure what to do. +## Step 5: format code + +To format the exercise's code, follow these steps: + +- Open a command prompt in the `language/csharp` directory. +- Run `./format.ps1 `. This script will format the code using the [`dotnet format` tool][dotnet-format]. + ## Inspiration When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [datetimes][concept-exercise-datetimes] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. @@ -87,3 +94,4 @@ If you have any questions regarding implementing the exercise, please post them [concept-exercise-datetimes]: ../exercises/concept/datetimes [concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers [reference]: ../../../reference +[dotnet-format]: https://github.com/dotnet/format From f876ac81fe16aec74db369de1edaf06612362146 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 18 Apr 2020 16:22:00 +0200 Subject: [PATCH 105/327] Add named parameter reference to basics exercise --- exercises/concept/basics/.docs/after.md | 6 ++++++ exercises/concept/basics/.docs/introduction.md | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md index a167fe687f..af35e7042f 100644 --- a/exercises/concept/basics/.docs/after.md +++ b/exercises/concept/basics/.docs/after.md @@ -35,6 +35,12 @@ Invoking a method is done by specifying its class- and method name and passing a var sum = Calculator.Add(1, 2); ``` +Arguments can optionally specify the corresponding parameter's name: + +```csharp +var sum = Calculator.Add(x: 1, y: 2); +``` + If the method to be called is defined in the same class as the method that calls it, the class name can be omitted. If a method does not use any class _state_ (which is the case in this exercise), the method can be made _static_ using the `static` modifier. Similarly, if a class only has static methods, it too can be made static using the `static` modifier. diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/basics/.docs/introduction.md index f51ff0b6be..bdba143fc6 100644 --- a/exercises/concept/basics/.docs/introduction.md +++ b/exercises/concept/basics/.docs/introduction.md @@ -42,6 +42,12 @@ Invoking a method is done by specifying its class- and method name and passing a var sum = Calculator.Add(1, 2); ``` +Arguments can optionally specify the corresponding parameter's name: + +```csharp +var sum = Calculator.Add(x: 1, y: 2); +``` + Scope in C# is defined between the `{` and `}` characters. C# supports two types of comments. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. From af5a3edf25b086f19e566797985e20b2c2df25ea Mon Sep 17 00:00:00 2001 From: Eli Flanagan Date: Tue, 21 Apr 2020 02:19:47 -0400 Subject: [PATCH 106/327] update header reference wording --- reference/out-of-scope.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md index dae4d22e7c..99f2c3fcc8 100644 --- a/reference/out-of-scope.md +++ b/reference/out-of-scope.md @@ -10,7 +10,7 @@ The document should answer the question The material should be capable of being communicated to an enquiring student as and when required. -Where material is covered under "What not to teach" in _design.md_ +Where material is covered under "Out of scope" in _design.md_ for a particular exercise it should not be repeated here unless it is felt that the topic otherwise has insufficient prominence. From 234dbfeb7f467b829430496a37e7fa79f0df5c82 Mon Sep 17 00:00:00 2001 From: Ken Jones Date: Tue, 21 Apr 2020 10:12:46 +0100 Subject: [PATCH 107/327] Update hints.md slight change to improve readability / wording --- exercises/concept/strings/.docs/hints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/strings/.docs/hints.md index 7cf72c7dcc..c9d469cc52 100644 --- a/exercises/concept/strings/.docs/hints.md +++ b/exercises/concept/strings/.docs/hints.md @@ -1,6 +1,6 @@ ### General -- The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction C# `string`'s. +- The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction to C# `string`s. - The `string` class has many useful [built-in methods][docs-string-methods]. ### 1. Get message from a log line From e03e4c7196eaf83f2e223d76403bdeeecb513621 Mon Sep 17 00:00:00 2001 From: Ken Jones Date: Tue, 21 Apr 2020 13:11:05 +0100 Subject: [PATCH 108/327] Update implementing-a-concept-exercise.md slight amendment to wording, sorry if these are annoying! --- reference/implementing-a-concept-exercise.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 6fab139654..60f223c0eb 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -6,7 +6,7 @@ This document describes how to implement a concept exercise for the C# track. - [The features of v3][docs-features-of-v3]. - [Rationale for v3][docs-rationale-for-v3]. -- [What are concept exercise and how they are structured?][docs-concept-exercises] +- [What are concept exercises and how are they structured?][docs-concept-exercises] Please also watch the following video: From 311e1df8cc263ff4d2f0d1be78eabbb7d5f7122c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 22 Apr 2020 11:21:40 +0200 Subject: [PATCH 109/327] add auto formatting support add auto formatting support --- reference/implementing-a-concept-exercise.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 60f223c0eb..9b8e409ef3 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -69,10 +69,17 @@ Skip this step if you're not sure what to do. ## Step 5: format code -To format the exercise's code, follow these steps: +All C# code should be formatted using the [`dotnet format` tool][dotnet-format]. There are two ways to format your C# code: -- Open a command prompt in the `language/csharp` directory. -- Run `./format.ps1 `. This script will format the code using the [`dotnet format` tool][dotnet-format]. +#### 1. Using a GitHub comment + +If you add a comment to a GitHub PR that contains the text `/dotnet-format`, a GitHub workflow will format all C# documents in the PR using `dotnet format`. Any formatting changes made by `dotnet format` will automatically be committed to the PR's branch. This also works for forks that have [enabled maintainers to edit the fork's PR][allowing-fork-pr-changes] (which is the default). + +#### 2. Using a script + +Open a command prompt in the `language/csharp` directory and then run: + +- `./format.ps1 `, where `` is the exercise's directory name. ## Inspiration @@ -95,3 +102,4 @@ If you have any questions regarding implementing the exercise, please post them [concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers [reference]: ../../../reference [dotnet-format]: https://github.com/dotnet/format +[allowing-fork-pr-changes]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork From 1ad49a20d3cfbc59e7d7da8fffd43e2ebf36f3f0 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 22 Apr 2020 14:41:19 +0200 Subject: [PATCH 110/327] New Concept Exercise: arrays Add arrays exercise Co-authored-by: Jeremy Walker Co-authored-by: wolf99 <281700+wolf99@users.noreply.github.com> --- exercises/concept/arrays/.docs/after.md | 83 +++++++++++++++++++ exercises/concept/arrays/.docs/hints.md | 39 +++++++++ .../concept/arrays/.docs/instructions.md | 57 +++++++++++++ .../concept/arrays/.docs/introduction.md | 41 +++++++++ exercises/concept/arrays/.meta/Example.cs | 53 ++++++++++++ exercises/concept/arrays/.meta/config.json | 8 ++ exercises/concept/arrays/.meta/design.md | 56 +++++++++++++ exercises/concept/arrays/Arrays.cs | 36 ++++++++ exercises/concept/arrays/Arrays.csproj | 13 +++ exercises/concept/arrays/ArraysTests.cs | 74 +++++++++++++++++ 10 files changed, 460 insertions(+) create mode 100644 exercises/concept/arrays/.docs/after.md create mode 100644 exercises/concept/arrays/.docs/hints.md create mode 100644 exercises/concept/arrays/.docs/instructions.md create mode 100644 exercises/concept/arrays/.docs/introduction.md create mode 100644 exercises/concept/arrays/.meta/Example.cs create mode 100644 exercises/concept/arrays/.meta/config.json create mode 100644 exercises/concept/arrays/.meta/design.md create mode 100644 exercises/concept/arrays/Arrays.cs create mode 100644 exercises/concept/arrays/Arrays.csproj create mode 100644 exercises/concept/arrays/ArraysTests.cs diff --git a/exercises/concept/arrays/.docs/after.md b/exercises/concept/arrays/.docs/after.md new file mode 100644 index 0000000000..80ee0f5c8c --- /dev/null +++ b/exercises/concept/arrays/.docs/after.md @@ -0,0 +1,83 @@ +Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: + +```csharp +// Declare array with explicit size (size is 2) +int[] twoInts = new int[2]; + +// Assign first and second element by index +twoInts[0] = 7; +twoInts[1] = 8; + +// Retrieve the second element by index +twoInts[1] == 8; // => true + +// Check the length of the array +twoInts.Length == 2; // => true +``` + +Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: + +```csharp +// Three equivalent ways to declare and initialize an array (size is 3) +int[] threeIntsV1 = new int[] { 4, 9, 7 }; +int[] threeIntsV2 = new[] { 4, 9, 7 }; +int[] threeIntsV3 = { 4, 9, 7 }; +``` + +Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. + +An array is also a _collection_, which means that you can iterate over all its values using a [`foreach` loop][foreach-statement]: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // Output the vowel + System.Console.Write(vowel); +} + +// => aeiou +``` + +One could use a [`for` loop][for-statement] to iterate over an array: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +for (int i = 0; i < vowels.Length; i++) +{ + // Output the vowel + System.Console.Write(vowels[i]); +} + +// => aeiou +``` + +However, generally a `foreach` loop is preferrable over a `for` loop for the following reasons: + +- A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. +- A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. +- A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. + +To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // This would result in a compiler error + // vowel = 'Y'; +} +``` + +[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[array-class]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 +[array-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties +[array-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods +[foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in +[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for +[break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/arrays/.docs/hints.md new file mode 100644 index 0000000000..372b0f00df --- /dev/null +++ b/exercises/concept/arrays/.docs/hints.md @@ -0,0 +1,39 @@ +### General + +- The bird count per day is stored in a [field][fields] named `birdsPerDay`. +- The bird count per day is an array that contains exactly 7 integers. + +### 1. Check what the counts were last week + +- As this method does _not_ depend on the current week's count, it is defined as a [`static` method][static-members]. +- There are [several ways to define an array][single-dimensional-arrays]. + +### 2. Check how many birds visited yesterday + +- Remember that the counts are ordered by day from oldest to most recent, with the last element representing today. +- Accessing the second last element can be done either by using its (fixed) index (remember to start counting from zero) or by calculating its index using the [array's size][array-length]. + +### 3. Calculate the total number of visiting birds + +- A variable can be used to hold the total number of visiting birds. +- The array can be iterated over using a [`foreach` loop][array-foreach]. +- The variable can be updated inside the loop. + +### 4. Calculate the number of busy days + +- A variable can be used to hold the number of busy days. +- The array can be iterated over using a [`foreach` loop][array-foreach]. +- The variable can be updated inside the loop. +- A [conditional statement][if-statement] can be used inside the loop. + +### 5. Check if there was a day with no visiting birds + +- The `Array` class has a [built-in method][array-indexof] to check at which index an element can be found. A special value is returned if a matching element could not be found. + +[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[static-members]: https://www.oreilly.com/library/view/programming-c/0596001177/ch04s03.html +[array-indexof]: https://docs.microsoft.com/en-us/dotnet/api/system.array.indexof?view=netcore-3.1#System_Array_IndexOf_System_Array_System_Object_ +[if-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else +[array-length]: https://docs.microsoft.com/en-us/dotnet/api/system.array.length?view=netcore-3.1 diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md new file mode 100644 index 0000000000..29c22d99eb --- /dev/null +++ b/exercises/concept/arrays/.docs/instructions.md @@ -0,0 +1,57 @@ +You're an avid bird watcher that keeps track of how many birds have visited your garden in the last seven days. + +You have five tasks, all dealing with the numbers of birds that visited your garden. + +### 1. Check what the counts were last week + +For comparison purposes, you always keep a copy of last week's counts nearby, which were: 0, 2, 5, 3, 7, 8 and 4. Implement the `BirdCount.LastWeek()` method that returns last week's counts: + +```csharp +BirdCount.LastWeek(); +// => [0, 2, 5, 3, 7, 8, 4] +``` + +### 2. Check how many birds visited yesterday + +Implement the `BirdCount.Yesterday()` method to return how many birds visited your garden yesterday. The bird counts are ordered by day, with the first element being the count of the oldest day, and the last element being today's count. + +```csharp +int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; +var birdCount = new BirdCount(birdsPerDay); +birdCount.Yesterday(); +// => 4 +``` + +### 3. Calculate the total number of visiting birds + +Implement the `BirdCount.Total()` method to return the total number of birds that have visited your garden: + +```csharp +int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; +var birdCount = new BirdCount(birdsPerDay); +birdCount.Total(); +// => 19 +``` + +### 4. Calculate the number of busy days + +Some days are busier that others. A busy day is one where five or more birds have visited your garden. +Implement the `BirdCount.BusyDays()` method to return the number of busy days: + +```csharp +int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; +var birdCount = new BirdCount(birdsPerDay); +birdCount.BusyDays(); +// => 2 +``` + +### 5. Check if there was a day with no visiting birds + +Implement the `BirdCount.HasDayWithoutBirds()` method that returns `true` if there was a day at which zero birds visited the garden; otherwise, return `false`: + +```csharp +int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; +var birdCount = new BirdCount(birdsPerDay); +birdCount.HasDayWithoutBirds(); +// => true +``` diff --git a/exercises/concept/arrays/.docs/introduction.md b/exercises/concept/arrays/.docs/introduction.md new file mode 100644 index 0000000000..4000fb2a48 --- /dev/null +++ b/exercises/concept/arrays/.docs/introduction.md @@ -0,0 +1,41 @@ +In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: + +```csharp +// Declare array with explicit size (size is 2) +int[] twoInts = new int[2]; + +// Assign first and second element by index +twoInts[0] = 7; +twoInts[1] = 8; + +// Retrieve the second element by index +twoInts[1] == 8; // => true + +// Check the length of the array +twoInts.Length == 2; // => true +``` + +Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: + +```csharp +// Three equivalent ways to declare and initialize an array (size is 3) +int[] threeIntsV1 = new int[] { 4, 9, 7 }; +int[] threeIntsV2 = new[] { 4, 9, 7 }; +int[] threeIntsV3 = { 4, 9, 7 }; +``` + +Arrays can be manipulated by either calling an array instance's methods or properties, or by using the static methods defined in the `Array` class. + +The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over all its values using a `foreach` loop: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // Output the vowel + System.Console.Write(vowel); +} + +// => aeiou +``` diff --git a/exercises/concept/arrays/.meta/Example.cs b/exercises/concept/arrays/.meta/Example.cs new file mode 100644 index 0000000000..0c4735e3ae --- /dev/null +++ b/exercises/concept/arrays/.meta/Example.cs @@ -0,0 +1,53 @@ +using System; + +public class BirdCount +{ + private int[] birdsPerDay; + + public BirdCount(int[] birdsPerDay) + { + this.birdsPerDay = birdsPerDay; + } + + public int Total() + { + var total = 0; + + foreach (var count in birdsPerDay) + { + total += count; + } + + return total; + } + + public int BusyDays() + { + var days = 0; + + foreach (var count in birdsPerDay) + { + if (count >= 5) + { + days++; + } + } + + return days; + } + + public int Yesterday() + { + return birdsPerDay[5]; + } + + public bool HasDayWithoutBirds() + { + return Array.IndexOf(birdsPerDay, 0) != -1; + } + + public static int[] LastWeek() + { + return new int[] { 0, 2, 5, 3, 7, 8, 4 }; + } +} diff --git a/exercises/concept/arrays/.meta/config.json b/exercises/concept/arrays/.meta/config.json new file mode 100644 index 0000000000..6d4e44d872 --- /dev/null +++ b/exercises/concept/arrays/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md new file mode 100644 index 0000000000..c8f9226dcb --- /dev/null +++ b/exercises/concept/arrays/.meta/design.md @@ -0,0 +1,56 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Arrays in C#. + +Of the many available C# collection types, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons: + +- Arrays don't require the student to know about generics. +- Arrays are a common data type in many languages. +- Arrays have a fixed length. No complexity in adding or removing elements. +- Arrays have a simple shorthand syntax. No need to understand how constructors work to define an array. + +## Learning objectives + +- The existence of the `Array` type. +- Defining an array. +- Accessing elements in an array by index. +- Iterating over elements in an array. +- Basic array functions (like finding the index of an element in an array). + +## Out of scope + +- Multi-dimensional/jagged arrays. +- Memory and performance characteristics of arrays. +- Enumerables. +- Iterators. +- LINQ. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `arrays`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). +- `foreach-loops`: know how to iterate over a collection. + +## Prequisites + +This exercise's prerequisites Concepts are: + +- `classes`: know how to work with fields. +- `for-loops`: know what a `for` loop is. +- `booleans`: know what a `bool` is. +- `basics`: know how to work with `integers` and how to assign and update variables. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/arrays/Arrays.cs new file mode 100644 index 0000000000..8522a323fb --- /dev/null +++ b/exercises/concept/arrays/Arrays.cs @@ -0,0 +1,36 @@ +using System; + +public class BirdCount +{ + private int[] birdsPerDay; + + public BirdCount(int[] birdsPerDay) + { + this.birdsPerDay = birdsPerDay; + } + + public static int[] LastWeek() + { + throw new NotImplementedException("Please implement the BirdCount.LastWeek method"); + } + + public int Yesterday() + { + throw new NotImplementedException("Please implement the BirdCount.Yesterday method"); + } + + public int Total() + { + throw new NotImplementedException("Please implement the BirdCount.Total method"); + } + + public int BusyDays() + { + throw new NotImplementedException("Please implement the BirdCount.BusyDays method"); + } + + public bool HasDayWithoutBirds() + { + throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds method"); + } +} diff --git a/exercises/concept/arrays/Arrays.csproj b/exercises/concept/arrays/Arrays.csproj new file mode 100644 index 0000000000..796fae8ebb --- /dev/null +++ b/exercises/concept/arrays/Arrays.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/arrays/ArraysTests.cs b/exercises/concept/arrays/ArraysTests.cs new file mode 100644 index 0000000000..9d6add90a7 --- /dev/null +++ b/exercises/concept/arrays/ArraysTests.cs @@ -0,0 +1,74 @@ +using Xunit; + +public class BirdCountTests +{ + [Fact(Skip = "Remove this Skip property to run this test")] + public void LastWeek() + { + Assert.Equal(new int[] { 0, 2, 5, 3, 7, 8, 4 }, BirdCount.LastWeek()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void YesterdayForDisappointingWeek() + { + var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; + var birdCount = new BirdCount(counts); + Assert.Equal(1, birdCount.Yesterday()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void YesterdayDaysForBusyWeek() + { + var counts = new int[] { 8, 8, 9, 5, 4, 7, 10 }; + var birdCount = new BirdCount(counts); + Assert.Equal(7, birdCount.Yesterday()); + } + + [Fact] + public void TotalForDisappointingWeek() + { + var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; + var birdCount = new BirdCount(counts); + Assert.Equal(2, birdCount.Total()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TotalForBusyWeek() + { + var counts = new int[] { 5, 9, 12, 6, 8, 8, 17 }; + var birdCount = new BirdCount(counts); + Assert.Equal(65, birdCount.Total()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BusyDaysForDisappointingWeek() + { + var counts = new int[] { 1, 1, 1, 0, 0, 0, 0 }; + var birdCount = new BirdCount(counts); + Assert.Equal(0, birdCount.BusyDays()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BusyDaysForBusyWeek() + { + var counts = new int[] { 4, 9, 5, 7, 8, 8, 2 }; + var birdCount = new BirdCount(counts); + Assert.Equal(5, birdCount.BusyDays()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void HasDayWithoutBirdsWithDayWithoutBirds() + { + var counts = new int[] { 5, 5, 4, 0, 7, 6, 7 }; + var birdCount = new BirdCount(counts); + Assert.True(birdCount.HasDayWithoutBirds()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void HasDayWithoutBirdsWithNoDayWithoutBirds() + { + var counts = new int[] { 4, 5, 9, 10, 9, 4, 3 }; + var birdCount = new BirdCount(counts); + Assert.False(birdCount.HasDayWithoutBirds()); + } +} From 880ae07dd5138dcd0c46d457902a6553a2c2e357 Mon Sep 17 00:00:00 2001 From: Marcos Almeida Date: Thu, 23 Apr 2020 09:13:21 +0200 Subject: [PATCH 111/327] Implement new Concept Exercise: nullability Implement new Concept Exercise: nullability Co-authored-by: Erik Schierboom Co-authored-by: Silvano Cerza <3314350+silvanocerza@users.noreply.github.com> Co-authored-by: Jeremy Walker Co-authored-by: wolf99 Co-authored-by: Mike May Co-authored-by: mikedamay Co-authored-by: Derk-Jan Karrenbeld Co-authored-by: mikedamay Co-authored-by: Eli Flanagan Co-authored-by: wolf99 Co-authored-by: Johan Berg <47738833+bergjohan@users.noreply.github.com> Co-authored-by: Rob Keim Co-authored-by: Sascha Mann Co-authored-by: wolf99 <281700+wolf99@users.noreply.github.com> --- exercises/concept/nullability/.docs/after.md | 60 ++++++++++++ exercises/concept/nullability/.docs/hints.md | 38 ++++++++ .../concept/nullability/.docs/instructions.md | 37 +++++++ .../concept/nullability/.docs/introduction.md | 96 +++++++++++++++++++ .../concept/nullability/.meta/Example.cs | 27 ++++++ .../concept/nullability/.meta/config.json | 8 ++ exercises/concept/nullability/.meta/design.md | 50 ++++++++++ exercises/concept/nullability/Nullability.cs | 16 ++++ .../concept/nullability/Nullability.csproj | 14 +++ .../concept/nullability/NullabilityTests.cs | 40 ++++++++ 10 files changed, 386 insertions(+) create mode 100644 exercises/concept/nullability/.docs/after.md create mode 100644 exercises/concept/nullability/.docs/hints.md create mode 100644 exercises/concept/nullability/.docs/instructions.md create mode 100644 exercises/concept/nullability/.docs/introduction.md create mode 100644 exercises/concept/nullability/.meta/Example.cs create mode 100644 exercises/concept/nullability/.meta/config.json create mode 100644 exercises/concept/nullability/.meta/design.md create mode 100644 exercises/concept/nullability/Nullability.cs create mode 100644 exercises/concept/nullability/Nullability.csproj create mode 100644 exercises/concept/nullability/NullabilityTests.cs diff --git a/exercises/concept/nullability/.docs/after.md b/exercises/concept/nullability/.docs/after.md new file mode 100644 index 0000000000..c379ac7b90 --- /dev/null +++ b/exercises/concept/nullability/.docs/after.md @@ -0,0 +1,60 @@ +Sometimes we need to make it so that variables have no particular +value, i.e. they are empty. In C#, this corresponds to the [literal +`null`][null-keyword]. + +In this exercise, we saw the definition of [nullable +types][nullable-types-tutorial], and how the compiler and runtime of +C# help us dealing with `null` values. + +At compilation time, [the operator `?`][nullable-reference-types] will +declare a variable as being *nullable*. The compiler will then try to +help us avoiding calling methods on possibly `null` variables, by +raising warnings. You can use [the operator +`!`][null-forgiving-operator] to avoid warnings in places we are sure +a nullable variable is not null, but the compiler cannot detect +it. + +We can also use [the operators `??` and +`??=`][null-coalescing-operator] to provide a default value for a +nullable variable and [the operator `?.`][null-conditional-operator] +to chain accesses to methods, properties or attributes of potentially +`null` objects on an expression that evaluates to `null` instead of +throwing a `NullReferenceException`. + +```csharp +string? userName = null; // declares `userName` as a nullable string +Console.WriteLine(userName?.Length); // prints: "null", since `userName` is `null` +Console.WriteLine(userName ?? "default"); // prints: "default", since `userName` is `null` + +userName ??= "unknownUser"; // sets `userName` to "unknownUser" since its + // value was null +Console.WriteLine(userName!.Length); // prints "11" and avoids a compiler warning +``` + +At run time, calling any method or property on a +`null` value throws a `NullReferenceException` exception. +That is why it is important to always check if a nullable variable +is `null` before calling methods on its value. + +# Important changes in C# 8.0 + +Sometimes, we need to make sure that some variables are never +`null`. This simplifies code because it won't need to handle +`NullReferenceException`s or provide extra provisions for `null` +values. + +Before C# 8.0, reference types were nullable by default. For example, +a variable of type `string` may contain a `null` value, even it is not +declared as `string?`. + +For more information, refer to [this +][nullable-csharp-8] and [this][nullable-reference-types-tutorial] documents. + +[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null +[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ +[nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[null-forgiving-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving +[null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator +[null-conditional-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and- +[nullable-reference-types-tutorial]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types diff --git a/exercises/concept/nullability/.docs/hints.md b/exercises/concept/nullability/.docs/hints.md new file mode 100644 index 0000000000..a02b634680 --- /dev/null +++ b/exercises/concept/nullability/.docs/hints.md @@ -0,0 +1,38 @@ +### General + +The following reference documentation may help you finishing this exercice: + +- [Null keyword][null-keyword]: reference documentation for `null` keyword. +- [Nullable types tutorial][nullable-types-tutorial]: basic tutorial on how to work with nullable types. +- [Nullable reference types][nullable-reference-types]: how to use nullable reference types. +- [Null-coalescing operator][null-coalescing-operator]: explains how the null-coalescing operator works. +- [Null-conditional operator][null-conditional-operator]: explains how the null-conditional operator works. +- [Nullable reference types tutorial][nullable-reference-types-tutorial]: tutorial on nullable reference types. + +### 1. Badge.Label + +* Which method from the `string` class may help you making the + department name [uppercase][toupper]? + +### 2. Badge.Label optional parameters + +* Do not forget to add `GUEST` as the department name if there's no + provided department name. + +### 2. Badge.PrintLabel + +* Which method from the `string` class may help you to extract a + [substring][substring] + of a string? +* Do all slices always have the same length? If not, how can you handle + this case? +* Do not forget the `prefix` should fit on the `maximumWidth` + +[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null +[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ +[null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator +[null-conditional-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator +[nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[nullable-reference-types-tutorial]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types +[substring]: https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=netframework-4.8 +[toupper]: https://docs.microsoft.com/en-us/dotnet/api/system.string.toupper?view=netframework-4.8xv diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/nullability/.docs/instructions.md new file mode 100644 index 0000000000..3a1b40b565 --- /dev/null +++ b/exercises/concept/nullability/.docs/instructions.md @@ -0,0 +1,37 @@ +In this exercise you'll be writing code to helping printing name +badges for factory employees. + +Employees have an ID, name and department name. Badge labels are +formatted as follows: `"[id] - [name] - [DEPARTMENT]"` + +### 1. Generate an employee's badge label + +Implement the `Badge.Label()` method to return an employee's badge label: + +```csharp +Badge.Label(734, "Ernest Johnny Payne", "Strategic Communication"); +// => "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION" +``` + +### 2. Handle the optional parts of a badge label + +The ID and department name are optional. If someone does not have an +ID, do not print this part of the label. If someone has no +department, just print `GUEST` as their department name. + +### 3. Generate the actual text to be print on the badge + +Implement the `Badge.PrintLabel()` method to return an employee's +badge label that can fit on a badge with a given width. An optional +prefix may be added on the beginning of each line: + +```csharp +Badge.PrintLabel(" > ", "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION", 30); +// => " > [734] - Ernest Johnny Payne - \n> STRATEGIC COMMUNICATION" +// +// => Printed label: +// +// > [734] - Ernest Johnny Payne - +// > STRATEGIC COMMUNICATION + +``` diff --git a/exercises/concept/nullability/.docs/introduction.md b/exercises/concept/nullability/.docs/introduction.md new file mode 100644 index 0000000000..53c4c0c434 --- /dev/null +++ b/exercises/concept/nullability/.docs/introduction.md @@ -0,0 +1,96 @@ +In C#, the `null` literal is used to denote the absence of a value. A +*nullable* type is a type that allows `null` values. By default +reference types are nullable and value types are non nullable. The +`?` suffix to a variable's type makes it nullable if it is not. From +C# 8.0 on, one can [make reference types non nullable by +default][nullable-csharp-8], just like value types. + +```csharp +int? nullable = 5; +nullable = null; + +int nonNullable = 5; + +// Would result in compile error as type is not nullable +// nonNullable = null; +``` + +A common mistake is to access a member (e.g. a method or property) on a nullable +variable whose value is `null`. This will cause the C# runtime +to raise a `NullReferenceException`. + +The C# compiler can help us avoiding such errors. If we try to +compile the following code: + +```csharp +string? userName = ...; + +... + +Console.WriteLine(userName.Length); +``` + +The compiler will give the following warning message: + +``` +Dereference of a possibly null reference. (CS8602) +``` + +A good practice is testing if a nullable value is not `null` before +trying to do something with it. There are some cases however, where we +know for sure that, given the context, a variable cannot be `null`. + +In order to dismiss the warning, we can use the operator `!`: + +```csharp +Console.WriteLine(userName!.Length); +``` + +Finally, sometimes, we want to provide a default value to a variable, +in case it is `null`. We know how to use an `if` block to check +that. However, the more nullable variables we need to check, the more +cumbersome it gets. + +The `??` and `?.` operators are a simple shortcuts for that: + +```csharp +// prints: "default" if `userName` is `null` +Console.WriteLine(userName ?? "default"); + +// This code is equivalent to: +string userNameValue; +if (userName == null) +{ + userNameValue = "default"; +} +else +{ + userNameValue = userName; +} +Console.WriteLine(userNameValue); + + + +// prints: `null` if `userName` is `null` +Console.WriteLine(userName?.Length); + +// This code is equivalent to +int userNameLength; +if (userName == null) +{ + userNameLength = 0; +} +else +{ + userNameLength = userName.Length; +} +Console.WriteLine(userNameLength); +``` + +With `A ?? B`, the C# runtime replaces the expression `A` with `B` if +`A` evaluates to `null`. The operator `?.` behaves similarly, the C# +runtime evaluates the expression `A?.B` by `null` if `A` is null, +without throwing a `NullReferenceException`. It executes `A.B` +otherwise. + +[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references diff --git a/exercises/concept/nullability/.meta/Example.cs b/exercises/concept/nullability/.meta/Example.cs new file mode 100644 index 0000000000..d38c363c96 --- /dev/null +++ b/exercises/concept/nullability/.meta/Example.cs @@ -0,0 +1,27 @@ +using System; + +public static class Badge +{ + public static string Label(int? id, string name, string? department) + { + var idLabel = (id == null ? "" : $"[{id}] - "); + return $"{idLabel}{name} - {department?.ToUpper() ?? "GUEST"}"; + } + + public static string PrintLabel(string? prefix, + string label, + int maximumWidth) + { + maximumWidth -= prefix?.Length ?? 0; + + var output = ""; + for (int i = 0; i < label.Length; i += maximumWidth) + { + output += (prefix ?? "") + + label.Substring(i, Math.Min(maximumWidth, + label.Length - i)) + "\n"; + } + return output.TrimEnd(); + } + +} diff --git a/exercises/concept/nullability/.meta/config.json b/exercises/concept/nullability/.meta/config.json new file mode 100644 index 0000000000..1c6ef680dd --- /dev/null +++ b/exercises/concept/nullability/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "maurelio1234", + "exercism_username": "maurelio1234" + } + ] +} diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md new file mode 100644 index 0000000000..bca3a22d32 --- /dev/null +++ b/exercises/concept/nullability/.meta/design.md @@ -0,0 +1,50 @@ +# Design + +## Goal + +The goal of this exercise is to introduce the student to the concept of [Nullability in C#][null-keyword]. + +## Learning objectives + +- Know of the existence of the `null` literal. +- Know what a `NullReferenceException` is and when it is thrown. +- Know how to compare a value to `null`. +- Know the difference between value and reference types regarding nullability, especially pre C# 8.0. +- Know how to define nullable reference and value types. +- Know about the null-related operators (`!`, `?`, `??`). +- Know about basic null checking by the compiler. + +## Out of scope + +- Nullable attributes. +- In-depth discussion of null checking by the compiler. +- Enabling C# 8 null checking. +- Casting using the `as` or `is` operator or using pattern matching. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `nullability`: know of the existence of the `null` literal; know what a `NullReferenceException` is and when it is thrown; know how to compare a value to `null`; know the difference between value and reference types regarding nullability; know how to define nullable reference and value types; know about the null-related operators; know about basic null checking by the compiler. + +## Prerequisites + +This Concept Exercise's prerequisites Concepts are: + +- `strings`: strings will be compared to `null` and basic methods from strings will be called. +- `basics`: integers will be compared to `null`, arithmetic operations will be performed on integers, variables will be introduced and updated. +- `exceptions`: explain how a `NullReferenceException` is thrown when accessing a `null` value. +- `for-loops`: strings will be processed and constructed iteratively. +- `memory-allocation`: reference and value types will be used in their nullable and non-nullable variants. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null diff --git a/exercises/concept/nullability/Nullability.cs b/exercises/concept/nullability/Nullability.cs new file mode 100644 index 0000000000..88f94e9b7e --- /dev/null +++ b/exercises/concept/nullability/Nullability.cs @@ -0,0 +1,16 @@ +using System; + +public static class Badge +{ + public static string Label(int? id, string name, string? department) + { + throw new NotImplementedException("Please implement the Badge.Label method"); + } + + public static string PrintLabel(string? prefix, + string label, + int maximumWidth) + { + throw new NotImplementedException("Please implement the Badge.PrintLabel method"); + } +} diff --git a/exercises/concept/nullability/Nullability.csproj b/exercises/concept/nullability/Nullability.csproj new file mode 100644 index 0000000000..66c16dd933 --- /dev/null +++ b/exercises/concept/nullability/Nullability.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp3.1 + enable + + + + + + + + + diff --git a/exercises/concept/nullability/NullabilityTests.cs b/exercises/concept/nullability/NullabilityTests.cs new file mode 100644 index 0000000000..e099fa4216 --- /dev/null +++ b/exercises/concept/nullability/NullabilityTests.cs @@ -0,0 +1,40 @@ +using Xunit; + +public class NullabilityTests +{ + [Fact] + public void FullName() => + Assert.Equal("[17] - Ryder Herbert - MARKETING", Badge.Label(17, "Ryder Herbert", "Marketing")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void MissingDepartment() => + Assert.Equal("[59] - Bogdan Rosario - GUEST", Badge.Label(59, "Bogdan Rosario", null)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void MissingId() => + Assert.Equal("Bogdan Rosario - MARKETING", Badge.Label(null, "Bogdan Rosario", "Marketing")); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void MissingDepartmentAndId() => + Assert.Equal("Bogdan Rosario - GUEST", Badge.Label(null, "Bogdan Rosario", null)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void PrintSingleLineWithoutPrefix() => + Assert.Equal("[23337] - Tilly Swift - SALES", Badge.PrintLabel(null, "[23337] - Tilly Swift - SALES", 150)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void PrintSingleLineWithPrefix() => + Assert.Equal(" > [23337] - Tilly Swift - SALES", Badge.PrintLabel(" > ", "[23337] - Tilly Swift - SALES", 150)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void PrintTwoLinesWithoutPrefix() => + Assert.Equal("[27] - Matilda \nCox - MARKETING", Badge.PrintLabel(null, "[27] - Matilda Cox - MARKETING", 15)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void PrintThreeLinesWithoutPrefix() => + Assert.Equal("[12] - Matilda \nLeanna Cox - EU\n MARKETING", Badge.PrintLabel("", "[12] - Matilda Leanna Cox - EU MARKETING", 15)); + + [Fact(Skip = "Remove this Skip property to run this test")] + public void PrintThreeLinesWithPrefix() => + Assert.Equal(" > [12] - Matilda \n > Leanna Cox - EU\n > MARKETING", Badge.PrintLabel(" > ", "[12] - Matilda Leanna Cox - EU MARKETING", 18)); +} From a0c63ed681149839985bdbc8eb0b9b14656d800d Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 23 Apr 2020 16:47:49 +0200 Subject: [PATCH 112/327] Fix formatting --- exercises/concept/nullability/.docs/after.md | 6 +++--- exercises/concept/nullability/.docs/hints.md | 20 +++++++++---------- .../concept/nullability/.docs/instructions.md | 6 +++--- .../concept/nullability/.docs/introduction.md | 14 ++++++------- 4 files changed, 23 insertions(+), 23 deletions(-) diff --git a/exercises/concept/nullability/.docs/after.md b/exercises/concept/nullability/.docs/after.md index c379ac7b90..bdb1b1cf4d 100644 --- a/exercises/concept/nullability/.docs/after.md +++ b/exercises/concept/nullability/.docs/after.md @@ -1,5 +1,5 @@ Sometimes we need to make it so that variables have no particular -value, i.e. they are empty. In C#, this corresponds to the [literal +value, i.e. they are empty. In C#, this corresponds to the [literal `null`][null-keyword]. In this exercise, we saw the definition of [nullable @@ -7,7 +7,7 @@ types][nullable-types-tutorial], and how the compiler and runtime of C# help us dealing with `null` values. At compilation time, [the operator `?`][nullable-reference-types] will -declare a variable as being *nullable*. The compiler will then try to +declare a variable as being _nullable_. The compiler will then try to help us avoiding calling methods on possibly `null` variables, by raising warnings. You can use [the operator `!`][null-forgiving-operator] to avoid warnings in places we are sure @@ -25,7 +25,7 @@ throwing a `NullReferenceException`. string? userName = null; // declares `userName` as a nullable string Console.WriteLine(userName?.Length); // prints: "null", since `userName` is `null` Console.WriteLine(userName ?? "default"); // prints: "default", since `userName` is `null` - + userName ??= "unknownUser"; // sets `userName` to "unknownUser" since its // value was null Console.WriteLine(userName!.Length); // prints "11" and avoids a compiler warning diff --git a/exercises/concept/nullability/.docs/hints.md b/exercises/concept/nullability/.docs/hints.md index a02b634680..14f78e1474 100644 --- a/exercises/concept/nullability/.docs/hints.md +++ b/exercises/concept/nullability/.docs/hints.md @@ -11,22 +11,22 @@ The following reference documentation may help you finishing this exercice: ### 1. Badge.Label -* Which method from the `string` class may help you making the - department name [uppercase][toupper]? +- Which method from the `string` class may help you making the + department name [uppercase][toupper]? ### 2. Badge.Label optional parameters -* Do not forget to add `GUEST` as the department name if there's no - provided department name. +- Do not forget to add `GUEST` as the department name if there's no + provided department name. ### 2. Badge.PrintLabel -* Which method from the `string` class may help you to extract a - [substring][substring] - of a string? -* Do all slices always have the same length? If not, how can you handle - this case? -* Do not forget the `prefix` should fit on the `maximumWidth` +- Which method from the `string` class may help you to extract a + [substring][substring] + of a string? +- Do all slices always have the same length? If not, how can you handle + this case? +- Do not forget the `prefix` should fit on the `maximumWidth` [null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null [nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/nullability/.docs/instructions.md index 3a1b40b565..c3231a3177 100644 --- a/exercises/concept/nullability/.docs/instructions.md +++ b/exercises/concept/nullability/.docs/instructions.md @@ -16,7 +16,7 @@ Badge.Label(734, "Ernest Johnny Payne", "Strategic Communication"); ### 2. Handle the optional parts of a badge label The ID and department name are optional. If someone does not have an -ID, do not print this part of the label. If someone has no +ID, do not print this part of the label. If someone has no department, just print `GUEST` as their department name. ### 3. Generate the actual text to be print on the badge @@ -28,10 +28,10 @@ prefix may be added on the beginning of each line: ```csharp Badge.PrintLabel(" > ", "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION", 30); // => " > [734] - Ernest Johnny Payne - \n> STRATEGIC COMMUNICATION" -// +// // => Printed label: // -// > [734] - Ernest Johnny Payne - +// > [734] - Ernest Johnny Payne - // > STRATEGIC COMMUNICATION ``` diff --git a/exercises/concept/nullability/.docs/introduction.md b/exercises/concept/nullability/.docs/introduction.md index 53c4c0c434..3f53a2534e 100644 --- a/exercises/concept/nullability/.docs/introduction.md +++ b/exercises/concept/nullability/.docs/introduction.md @@ -1,6 +1,6 @@ -In C#, the `null` literal is used to denote the absence of a value. A -*nullable* type is a type that allows `null` values. By default -reference types are nullable and value types are non nullable. The +In C#, the `null` literal is used to denote the absence of a value. A +_nullable_ type is a type that allows `null` values. By default +reference types are nullable and value types are non nullable. The `?` suffix to a variable's type makes it nullable if it is not. From C# 8.0 on, one can [make reference types non nullable by default][nullable-csharp-8], just like value types. @@ -16,7 +16,7 @@ int nonNullable = 5; ``` A common mistake is to access a member (e.g. a method or property) on a nullable -variable whose value is `null`. This will cause the C# runtime +variable whose value is `null`. This will cause the C# runtime to raise a `NullReferenceException`. The C# compiler can help us avoiding such errors. If we try to @@ -59,7 +59,7 @@ Console.WriteLine(userName ?? "default"); // This code is equivalent to: string userNameValue; -if (userName == null) +if (userName == null) { userNameValue = "default"; } @@ -74,9 +74,9 @@ Console.WriteLine(userNameValue); // prints: `null` if `userName` is `null` Console.WriteLine(userName?.Length); -// This code is equivalent to +// This code is equivalent to int userNameLength; -if (userName == null) +if (userName == null) { userNameLength = 0; } From 2fc57c6ba837c411735b162243d5ff76116507b1 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 23 Apr 2020 17:01:49 +0200 Subject: [PATCH 113/327] Cross-reference concept exercise file information [Docs] Cross-reference concept exercise file information --- reference/implementing-a-concept-exercise.md | 88 ++++++++++++++++---- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 9b8e409ef3..aece63bf19 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -19,7 +19,7 @@ As this document is generic, the following placeholders are used: Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what not). This information can be found in the exercise's GitHub issue. Having done this, please read the [C# concept exercises introduction][concept-exercises]. -To implement a concept exercise, the following files must be created: +To implement a concept exercise, the following files must be added:
 languages
@@ -28,11 +28,11 @@ languages
         └── concept
             └── <SLUG>
                 ├── .docs
+                |   ├── after.md
                 |   ├── instructions.md
                 |   ├── introduction.md
                 |   ├── hints.md
-                |   ├── source.md (required if there are third-party sources)
-                |   └── after.md
+                |   └── source.md (required if there are third-party sources)
                 ├── .meta
                 |   |── config.json
                 |   |── design.md
@@ -42,32 +42,50 @@ languages
                 └── <NAME>Tests.cs
 
-## Step 1: adding track-specific files +## Step 1: Add code files -These files are specific to the C# track: +The code files are track-specific and should be designed to help the student learn the exercise's concepts. The following C# code files must be added (not necessarily in this order): -- `.cs`. the stub implementation file, which is the starting point for students to work on the exercise. -- `.csproj`: the C# project file. -- `Tests.cs`: the test suite. -- `.meta/Example.cs`: an example implementation that passes all the tests. +### Add`.cs` file -## Step 2: adding common files +**Purpose:** Provide a stub implementation. -How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. +- The stub implementation's code should compile. The only exception is for exercises that introduce syntax we _want_ a student to define themselves, like how to define a class or property. In this case, insert a descriptive TODO comment instead of providing stub code (see [this example][todo]). +- Stub methods should throw a `NotImplementedException` which message contains the method to implement (see [this example][not-implemented]). -## Step 3: add analyzer (optional) +For more information, please read [this in-depth description][stub-file], [watch this video][video-stub-file] and check [this example stub file][example-stub-file]. -Some exercises could benefit from having an exercise-specific [analyzer][analyzer]. If so, specify what analysis rules should be applied to this exercise and why. +### Add`Tests.cs` file -Skip this step if you're not sure what to do. +**Purpose:** The test suite to verify a solution's correctness. -## Step 4: custom representation (optional) +- [xUnit][xunit] is used as the test framework. +- Only use `Fact` tests; don't use `Theory` tests. +- All but the first test should be skipped by default (check [this example][skip-fact]). -Some exercises could benefit from having an custom representation as generated by the [C# representer][representer]. If so, specify what changes to the representation should be applied and why. +For more information, please read [this in-depth description][tests-file], [watch this video][video-tests-file] and check [this example tests file][example-tests-file]. + +### Add`.csproj` file + +**Purpose:** The project file required to build the project and run the tests. + +For more information, check [this example project file][example-project-file]. -Skip this step if you're not sure what to do. +### Add`.meta/Example.cs` file + +**Purpose:** The idiomatic example implementation that passes all the tests. + +For more information, please read [this in-depth description][example-file], [watch this video][video-example-file] and check [this example file][example-example-file]. + +## Step 2: Add documentation files + +How to create the files common to all tracks is described in the [how to implement a concept exercise document][how-to-implement-a-concept-exercise]. -## Step 5: format code +## Step 3: Update list of implemented exercises + +- Add the exercise to the [list of implemented exercises][implemented-exercises]. + +## Step 4: format code All C# code should be formatted using the [`dotnet format` tool][dotnet-format]. There are two ways to format your C# code: @@ -81,6 +99,18 @@ Open a command prompt in the `language/csharp` directory and then run: - `./format.ps1 `, where `` is the exercise's directory name. +## Step 5: Add analyzer (optional) + +Some exercises could benefit from having an exercise-specific [analyzer][analyzer]. If so, specify what analysis rules should be applied to this exercise and why. + +_Skip this step if you're not sure what to do._ + +## Step 6: Add representation (optional) + +Some exercises could benefit from having an custom representation as generated by the [C# representer][representer]. If so, specify what changes to the representation should be applied and why. + +_Skip this step if you're not sure what to do._ + ## Inspiration When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [datetimes][concept-exercise-datetimes] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. @@ -103,3 +133,25 @@ If you have any questions regarding implementing the exercise, please post them [reference]: ../../../reference [dotnet-format]: https://github.com/dotnet/format [allowing-fork-pr-changes]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork +[implemented-exercises]: ../exercises/concept/README.md#implemented-exercises +[video-stub-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1171 +[video-tests-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1255 +[video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781 +[example-stub-file]: ../exercises/concept/strings/Strings.cs +[example-tests-file]: ../exercises/concept/strings/StringsTests.cs +[example-example-file]: ../exercises/concept/strings/.meta/Example.cs +[example-project-file]: ../exercises/concept/strings/Strings.csproj +[skip-fact]: ../exercises/concept/strings/StringsTests.cs#L11 +[xunit]: https://xunit.net/ +[not-implemented]: ../exercises/concept/strings/Strings.cs#L5 +[todo]: ../exercises/concept/basics/Basics.cs +[stub-file]: ../../../docs/concept-exercises.md#stub-implementation-file +[tests-file]: ../../../docs/concept-exercises.md#tests-file +[example-file]: ../../../docs/concept-exercises.md#example-implementation-file +[video-stub-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1171 +[video-tests-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1255 +[video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781 +[example-stub-file]: ../languages/csharp/exercises/concept/strings/Strings.cs +[example-tests-file]: ../languages/csharp/exercises/concept/strings/StringsTests.cs +[example-example-file]: ../languages/csharp/exercises/concept/strings/.meta/Example.cs +[example-project-file]: ../exercises/concept/strings/Strings.csproj From c12f4aa279d2541aaad1ccf83fbed57a1de0f360 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 23 Apr 2020 17:36:41 +0200 Subject: [PATCH 114/327] Update Microsoft.NET.Test.Sdk package to 16.6.0 --- exercises/concept/arrays/Arrays.csproj | 2 +- exercises/concept/basics/Basics.csproj | 2 +- exercises/concept/datetimes/DateTimes.csproj | 2 +- exercises/concept/enums/Enums.csproj | 2 +- exercises/concept/flag-enums/FlagEnums.csproj | 2 +- .../concept/floating-point-numbers/FloatingPointNumbers.csproj | 2 +- exercises/concept/numbers/Numbers.csproj | 2 +- exercises/concept/strings/Strings.csproj | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/exercises/concept/arrays/Arrays.csproj b/exercises/concept/arrays/Arrays.csproj index 796fae8ebb..6769a865d6 100644 --- a/exercises/concept/arrays/Arrays.csproj +++ b/exercises/concept/arrays/Arrays.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/basics/Basics.csproj b/exercises/concept/basics/Basics.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/basics/Basics.csproj +++ b/exercises/concept/basics/Basics.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/datetimes/DateTimes.csproj b/exercises/concept/datetimes/DateTimes.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/datetimes/DateTimes.csproj +++ b/exercises/concept/datetimes/DateTimes.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/enums/Enums.csproj b/exercises/concept/enums/Enums.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/enums/Enums.csproj +++ b/exercises/concept/enums/Enums.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/flag-enums/FlagEnums.csproj b/exercises/concept/flag-enums/FlagEnums.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/flag-enums/FlagEnums.csproj +++ b/exercises/concept/flag-enums/FlagEnums.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj b/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/numbers/Numbers.csproj b/exercises/concept/numbers/Numbers.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/numbers/Numbers.csproj +++ b/exercises/concept/numbers/Numbers.csproj @@ -5,7 +5,7 @@ - + diff --git a/exercises/concept/strings/Strings.csproj b/exercises/concept/strings/Strings.csproj index cfef7a3e96..8d66e73a50 100644 --- a/exercises/concept/strings/Strings.csproj +++ b/exercises/concept/strings/Strings.csproj @@ -5,7 +5,7 @@ - + From 4fda1f28979ff90a9a7092689dd69e43ee3c7d8c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 24 Apr 2020 13:40:06 +0200 Subject: [PATCH 115/327] Fix missing space --- reference/implementing-a-concept-exercise.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index aece63bf19..a3b9bc9320 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -46,7 +46,7 @@ languages The code files are track-specific and should be designed to help the student learn the exercise's concepts. The following C# code files must be added (not necessarily in this order): -### Add`.cs` file +### Add `.cs` file **Purpose:** Provide a stub implementation. @@ -55,7 +55,7 @@ The code files are track-specific and should be designed to help the student lea For more information, please read [this in-depth description][stub-file], [watch this video][video-stub-file] and check [this example stub file][example-stub-file]. -### Add`Tests.cs` file +### Add `Tests.cs` file **Purpose:** The test suite to verify a solution's correctness. @@ -65,13 +65,13 @@ For more information, please read [this in-depth description][stub-file], [watch For more information, please read [this in-depth description][tests-file], [watch this video][video-tests-file] and check [this example tests file][example-tests-file]. -### Add`.csproj` file +### Add `.csproj` file **Purpose:** The project file required to build the project and run the tests. For more information, check [this example project file][example-project-file]. -### Add`.meta/Example.cs` file +### Add `.meta/Example.cs` file **Purpose:** The idiomatic example implementation that passes all the tests. From 7df2dcb74c2fae238190ff8d0e7be90c1e058223 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 23 Apr 2020 14:30:30 +0200 Subject: [PATCH 116/327] Simplify exercise and update documentation --- exercises/concept/nullability/.docs/after.md | 126 ++++++++++++------ exercises/concept/nullability/.docs/hints.md | 45 +++---- .../concept/nullability/.docs/instructions.md | 46 +++---- .../concept/nullability/.docs/introduction.md | 118 +++++++--------- .../concept/nullability/.meta/Example.cs | 25 +--- exercises/concept/nullability/Nullability.cs | 11 +- .../concept/nullability/Nullability.csproj | 2 +- .../concept/nullability/NullabilityTests.cs | 44 +++--- 8 files changed, 196 insertions(+), 221 deletions(-) diff --git a/exercises/concept/nullability/.docs/after.md b/exercises/concept/nullability/.docs/after.md index bdb1b1cf4d..a7b26495cb 100644 --- a/exercises/concept/nullability/.docs/after.md +++ b/exercises/concept/nullability/.docs/after.md @@ -1,58 +1,100 @@ -Sometimes we need to make it so that variables have no particular -value, i.e. they are empty. In C#, this corresponds to the [literal -`null`][null-keyword]. - -In this exercise, we saw the definition of [nullable -types][nullable-types-tutorial], and how the compiler and runtime of -C# help us dealing with `null` values. - -At compilation time, [the operator `?`][nullable-reference-types] will -declare a variable as being _nullable_. The compiler will then try to -help us avoiding calling methods on possibly `null` variables, by -raising warnings. You can use [the operator -`!`][null-forgiving-operator] to avoid warnings in places we are sure -a nullable variable is not null, but the compiler cannot detect -it. - -We can also use [the operators `??` and -`??=`][null-coalescing-operator] to provide a default value for a -nullable variable and [the operator `?.`][null-conditional-operator] -to chain accesses to methods, properties or attributes of potentially -`null` objects on an expression that evaluates to `null` instead of -throwing a `NullReferenceException`. +In C#, the [`null` literal][null-keyword] is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values. + +Prior to C# 8.0, reference types were always nullable and value types were not. A [value type can be made nullable][nullable-value-types] though by appending it with a question mark (`?`). + +```csharp +string nullableReferenceType = "hello"; +nullableReferenceType = null; // Valid as type is nullable + +int nonNullableValueType = 5; +nonNullableValueType = null; // Compile error as type is not nullable + +int? nullableValueType = 5; // Define nullable value type +nullableValueType = null; // Valid as type is nullable +``` + +Accessing a member of a variable which value is `null` will compile fine, but result in a `NullReferenceException` being thrown at runtime: + +```csharp +string sentence = "What a nice day!"; + +// Throws NullReferenceException at runtime +sentence.Length; +``` + +To counter this common type of mistake, C# 8 allows one to [opt-into a feature][nullable-csharp-8] that makes [reference types non-nullable by default][nullable-reference-types]: + +```csharp +string nonNullableReferenceType = "book"; +nonNullableReferenceType = null; // Compile warning (no error!) + +string? nullableReferenceType = "movie"; +nullableReferenceType = null; // Valid as type is nullable +``` + +To [safely work with nullable values][nullable-types-tutorial], one should check if they are `null` before working with them: + +```csharp +string NormalizedName(string? name) +{ + if (name == null) + { + return "UNKNOWN"; + } + else + { + // Value is not null at this point, so no compile warning + // and no runtime NullReferenceException being thrown + return name.ToUpper(); + } +} + +NormalizedName(null); // => "UNKNOWN" +NormalizedName("Elisabeth"); // => "ELISABETH" +``` + +The [`??` operator][null-coalescing-operator] allows one to return a default value when the value is `null`: ```csharp -string? userName = null; // declares `userName` as a nullable string -Console.WriteLine(userName?.Length); // prints: "null", since `userName` is `null` -Console.WriteLine(userName ?? "default"); // prints: "default", since `userName` is `null` +string? name1 = "John"; +name1 ?? "Paul"; // => "John" -userName ??= "unknownUser"; // sets `userName` to "unknownUser" since its - // value was null -Console.WriteLine(userName!.Length); // prints "11" and avoids a compiler warning +string? name2 = null; +name2 ?? "George"; // => "George" ``` -At run time, calling any method or property on a -`null` value throws a `NullReferenceException` exception. -That is why it is important to always check if a nullable variable -is `null` before calling methods on its value. +The [`?.` operator][null-conditional-operator] allows one to call members safely on a possibly `null` value: -# Important changes in C# 8.0 +```csharp +string? fruit = "apple"; +fruit?.Length; // => 5 -Sometimes, we need to make sure that some variables are never -`null`. This simplifies code because it won't need to handle -`NullReferenceException`s or provide extra provisions for `null` -values. +string? vegetable = null; +vegetable?.Length; // => null +``` -Before C# 8.0, reference types were nullable by default. For example, -a variable of type `string` may contain a `null` value, even it is not -declared as `string?`. +If the compiler thinks a value could be `null` but you are certain it won't be, the [`!.` operator][null-forgiving-operator] can be used to suppress the warning. Only use this operator as a last resort though. -For more information, refer to [this -][nullable-csharp-8] and [this][nullable-reference-types-tutorial] documents. +```csharp +void PrintName(string? name) +{ + // Assume that the IsValid() method only return true + // when its argument is not null + if (IsValid(name)) + { + // No compile warning + Console.WriteLine(name!.Length); + } +} +``` + +If you'd like to learn more about working with nullable reference, check out [this tutorial][nullable-reference-types-tutorial]. +[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references [null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null [nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ [nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[nullable-value-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types [nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references [null-forgiving-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving [null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator diff --git a/exercises/concept/nullability/.docs/hints.md b/exercises/concept/nullability/.docs/hints.md index 14f78e1474..5a79189026 100644 --- a/exercises/concept/nullability/.docs/hints.md +++ b/exercises/concept/nullability/.docs/hints.md @@ -1,38 +1,23 @@ -### General +### 1. Print a badge for an employee -The following reference documentation may help you finishing this exercice: +- [String interpolation][string-interpolation] can be used to concisely format the badge. +- There is a [built-in method to convert a string to uppercase][toupper]. -- [Null keyword][null-keyword]: reference documentation for `null` keyword. -- [Nullable types tutorial][nullable-types-tutorial]: basic tutorial on how to work with nullable types. -- [Nullable reference types][nullable-reference-types]: how to use nullable reference types. -- [Null-coalescing operator][null-coalescing-operator]: explains how the null-coalescing operator works. -- [Null-conditional operator][null-conditional-operator]: explains how the null-conditional operator works. -- [Nullable reference types tutorial][nullable-reference-types-tutorial]: tutorial on nullable reference types. +### 2. Print a badge for a new employee -### 1. Badge.Label +- You should check if the ID is `null` before using it. +- [This tutorial goes into detail how to work with nullable value types][nullable-types-tutorial]. -- Which method from the `string` class may help you making the - department name [uppercase][toupper]? +### 3. Print a badge for the owner -### 2. Badge.Label optional parameters +- You should check if the department is `null` before using it. +- [This tutorial goes into detail how to work with nullable reference types][nullable-reference-types-tutorial]. +- The [null-conditional operator][null-conditional-operator] can be used to simplify calling a member on a nullable value. +- The [null-coalescing operator][null-coalescing-operator] can be used to simplify returning a different value if a nullable value is `null`. -- Do not forget to add `GUEST` as the department name if there's no - provided department name. - -### 2. Badge.PrintLabel - -- Which method from the `string` class may help you to extract a - [substring][substring] - of a string? -- Do all slices always have the same length? If not, how can you handle - this case? -- Do not forget the `prefix` should fit on the `maximumWidth` - -[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null -[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ -[null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator +[string-interpolation]: https://csharp.net-tutorials.com/operators/the-string-interpolation-operator/ +[null-coalescing-operator]: https://csharp.net-tutorials.com/operators/the-null-coalescing-operator/ [null-conditional-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator -[nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ [nullable-reference-types-tutorial]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types -[substring]: https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=netframework-4.8 -[toupper]: https://docs.microsoft.com/en-us/dotnet/api/system.string.toupper?view=netframework-4.8xv +[toupper]: https://docs.microsoft.com/en-us/dotnet/api/system.string.toupper?view=netcore-3.1 diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/nullability/.docs/instructions.md index c3231a3177..59237543ba 100644 --- a/exercises/concept/nullability/.docs/instructions.md +++ b/exercises/concept/nullability/.docs/instructions.md @@ -1,37 +1,37 @@ -In this exercise you'll be writing code to helping printing name -badges for factory employees. +In this exercise you'll be writing code to print name badges for factory employees. -Employees have an ID, name and department name. Badge labels are -formatted as follows: `"[id] - [name] - [DEPARTMENT]"` +### 1. Print a badge for an employee -### 1. Generate an employee's badge label - -Implement the `Badge.Label()` method to return an employee's badge label: +Employees have an ID, name and department name. Employee badge labels are formatted as follows: `"[id] - [name] - [DEPARTMENT]"`. Implement the `Badge.Print()` method to return an employee's badge label: ```csharp -Badge.Label(734, "Ernest Johnny Payne", "Strategic Communication"); +Badge.Print(734, "Ernest Johnny Payne", "Strategic Communication"); // => "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION" ``` -### 2. Handle the optional parts of a badge label +Note that the department should be uppercased on the label. + +### 2. Print a badge for a new employee -The ID and department name are optional. If someone does not have an -ID, do not print this part of the label. If someone has no -department, just print `GUEST` as their department name. +Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory. As badges are required, they will receive a temporary badge without the ID prefix. Modify the `Badge.Print()` method to support new employees that don't yet have an ID: + +```csharp +Badge.Print(id: null, "Jane Johnson", "Procurement"); +// => "Jane Johnson - PROCUREMENT" +``` -### 3. Generate the actual text to be print on the badge +### 3. Print a badge for the owner -Implement the `Badge.PrintLabel()` method to return an employee's -badge label that can fit on a badge with a given width. An optional -prefix may be added on the beginning of each line: +Even the factory's owner has to wear a badge at all times. However, an owner does not have a department. In this case, the label should print `"OWNER"` instead of the department name. Modify the `Badge.Print()` method to print a label for the owner: ```csharp -Badge.PrintLabel(" > ", "[734] - Ernest Johnny Payne - STRATEGIC COMMUNICATION", 30); -// => " > [734] - Ernest Johnny Payne - \n> STRATEGIC COMMUNICATION" -// -// => Printed label: -// -// > [734] - Ernest Johnny Payne - -// > STRATEGIC COMMUNICATION +Badge.Print(254, "Charlotte Hale", department: null); +// => "[254] - Charlotte Hale - OWNER" +``` +Note that it is possible for the owner to also be a new employee: + +```csharp +Badge.Print(id: null, "Charlotte Hale", department: null); +// => "Charlotte Hale - OWNER" ``` diff --git a/exercises/concept/nullability/.docs/introduction.md b/exercises/concept/nullability/.docs/introduction.md index 3f53a2534e..6ce9868e2e 100644 --- a/exercises/concept/nullability/.docs/introduction.md +++ b/exercises/concept/nullability/.docs/introduction.md @@ -1,96 +1,76 @@ -In C#, the `null` literal is used to denote the absence of a value. A -_nullable_ type is a type that allows `null` values. By default -reference types are nullable and value types are non nullable. The -`?` suffix to a variable's type makes it nullable if it is not. From -C# 8.0 on, one can [make reference types non nullable by -default][nullable-csharp-8], just like value types. +In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values. + +Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`). ```csharp -int? nullable = 5; -nullable = null; +string nullableReferenceType = "hello"; +nullableReferenceType = null; // Valid as type is nullable -int nonNullable = 5; +int nonNullableValueType = 5; +nonNullableValueType = null; // Compile error as type is not nullable -// Would result in compile error as type is not nullable -// nonNullable = null; +int? nullableValueType = 5; // Define nullable value type +nullableValueType = null; // Valid as type is nullable ``` -A common mistake is to access a member (e.g. a method or property) on a nullable -variable whose value is `null`. This will cause the C# runtime -to raise a `NullReferenceException`. - -The C# compiler can help us avoiding such errors. If we try to -compile the following code: +Accessing a member of a variable which value is `null` will compile fine, but result in a `NullReferenceException` being thrown at runtime: ```csharp -string? userName = ...; - -... - -Console.WriteLine(userName.Length); -``` - -The compiler will give the following warning message: +string sentence = null; +// Throws NullReferenceException at runtime +sentence.Length; ``` -Dereference of a possibly null reference. (CS8602) -``` - -A good practice is testing if a nullable value is not `null` before -trying to do something with it. There are some cases however, where we -know for sure that, given the context, a variable cannot be `null`. -In order to dismiss the warning, we can use the operator `!`: +To counter this common type of mistake, C# 8 allows one to opt-into a feature that makes reference types non-nullable by default: ```csharp -Console.WriteLine(userName!.Length); -``` +string nonNullableReferenceType = "book"; +nonNullableReferenceType = null; // Compile warning (no error!) -Finally, sometimes, we want to provide a default value to a variable, -in case it is `null`. We know how to use an `if` block to check -that. However, the more nullable variables we need to check, the more -cumbersome it gets. +string? nullableReferenceType = "movie"; +nullableReferenceType = null; // Valid as type is nullable +``` -The `??` and `?.` operators are a simple shortcuts for that: +To safely work with nullable values, one should check if they are `null` before working with them: ```csharp -// prints: "default" if `userName` is `null` -Console.WriteLine(userName ?? "default"); - -// This code is equivalent to: -string userNameValue; -if (userName == null) +string NormalizedName(string? name) { - userNameValue = "default"; + if (name == null) + { + return "UNKNOWN"; + } + else + { + // Value is not null at this point, so no compile warning + // and no runtime NullReferenceException being thrown + return name.ToUpper(); + } } -else -{ - userNameValue = userName; -} -Console.WriteLine(userNameValue); +NormalizedName(null); // => "UNKNOWN" +NormalizedName("Elisabeth"); // => "ELISABETH" +``` +The `??` operator allows one to return a default value when the value is `null`: -// prints: `null` if `userName` is `null` -Console.WriteLine(userName?.Length); +```csharp +string? name1 = "John"; +name1 ?? "Paul"; // => "John" -// This code is equivalent to -int userNameLength; -if (userName == null) -{ - userNameLength = 0; -} -else -{ - userNameLength = userName.Length; -} -Console.WriteLine(userNameLength); +string? name2 = null; +name2 ?? "George"; // => "George" ``` -With `A ?? B`, the C# runtime replaces the expression `A` with `B` if -`A` evaluates to `null`. The operator `?.` behaves similarly, the C# -runtime evaluates the expression `A?.B` by `null` if `A` is null, -without throwing a `NullReferenceException`. It executes `A.B` -otherwise. +The `?.` operator allows one to call members safely on a possibly `null` value: + +```csharp +string? fruit = "apple"; +fruit?.Length; // => 5 + +string? vegetable = null; +vegetable?.Length; // => null +``` [nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references diff --git a/exercises/concept/nullability/.meta/Example.cs b/exercises/concept/nullability/.meta/Example.cs index d38c363c96..46997ead85 100644 --- a/exercises/concept/nullability/.meta/Example.cs +++ b/exercises/concept/nullability/.meta/Example.cs @@ -1,27 +1,14 @@ -using System; - public static class Badge { - public static string Label(int? id, string name, string? department) - { - var idLabel = (id == null ? "" : $"[{id}] - "); - return $"{idLabel}{name} - {department?.ToUpper() ?? "GUEST"}"; - } - - public static string PrintLabel(string? prefix, - string label, - int maximumWidth) + public static string Print(int? id, string name, string? department) { - maximumWidth -= prefix?.Length ?? 0; + var worksAt = department?.ToUpper() ?? "OWNER"; - var output = ""; - for (int i = 0; i < label.Length; i += maximumWidth) + if (id == null) { - output += (prefix ?? "") + - label.Substring(i, Math.Min(maximumWidth, - label.Length - i)) + "\n"; + return $"{name} - {worksAt}"; } - return output.TrimEnd(); - } + return $"[{id}] {name} - {worksAt}"; + } } diff --git a/exercises/concept/nullability/Nullability.cs b/exercises/concept/nullability/Nullability.cs index 88f94e9b7e..c6a058028e 100644 --- a/exercises/concept/nullability/Nullability.cs +++ b/exercises/concept/nullability/Nullability.cs @@ -2,15 +2,8 @@ public static class Badge { - public static string Label(int? id, string name, string? department) + public static string Print(int? id, string name, string? department) { - throw new NotImplementedException("Please implement the Badge.Label method"); - } - - public static string PrintLabel(string? prefix, - string label, - int maximumWidth) - { - throw new NotImplementedException("Please implement the Badge.PrintLabel method"); + throw new NotImplementedException("Please implement the Badge.Print method"); } } diff --git a/exercises/concept/nullability/Nullability.csproj b/exercises/concept/nullability/Nullability.csproj index 66c16dd933..2583c2317b 100644 --- a/exercises/concept/nullability/Nullability.csproj +++ b/exercises/concept/nullability/Nullability.csproj @@ -6,7 +6,7 @@ - + diff --git a/exercises/concept/nullability/NullabilityTests.cs b/exercises/concept/nullability/NullabilityTests.cs index e099fa4216..cab573b8f4 100644 --- a/exercises/concept/nullability/NullabilityTests.cs +++ b/exercises/concept/nullability/NullabilityTests.cs @@ -3,38 +3,26 @@ public class NullabilityTests { [Fact] - public void FullName() => - Assert.Equal("[17] - Ryder Herbert - MARKETING", Badge.Label(17, "Ryder Herbert", "Marketing")); + public void LabelForEmployee() + { + Assert.Equal("[17] Ryder Herbert - MARKETING", Badge.Print(17, "Ryder Herbert", "Marketing")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MissingDepartment() => - Assert.Equal("[59] - Bogdan Rosario - GUEST", Badge.Label(59, "Bogdan Rosario", null)); + public void LabelForNewEmployee() + { + Assert.Equal("Bogdan Rosario - MARKETING", Badge.Print(null, "Bogdan Rosario", "Marketing")); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MissingId() => - Assert.Equal("Bogdan Rosario - MARKETING", Badge.Label(null, "Bogdan Rosario", "Marketing")); + public void LabelForOwner() + { + Assert.Equal("[59] Julie Sokato - OWNER", Badge.Print(59, "Julie Sokato", null)); + } [Fact(Skip = "Remove this Skip property to run this test")] - public void MissingDepartmentAndId() => - Assert.Equal("Bogdan Rosario - GUEST", Badge.Label(null, "Bogdan Rosario", null)); - - [Fact(Skip = "Remove this Skip property to run this test")] - public void PrintSingleLineWithoutPrefix() => - Assert.Equal("[23337] - Tilly Swift - SALES", Badge.PrintLabel(null, "[23337] - Tilly Swift - SALES", 150)); - - [Fact(Skip = "Remove this Skip property to run this test")] - public void PrintSingleLineWithPrefix() => - Assert.Equal(" > [23337] - Tilly Swift - SALES", Badge.PrintLabel(" > ", "[23337] - Tilly Swift - SALES", 150)); - - [Fact(Skip = "Remove this Skip property to run this test")] - public void PrintTwoLinesWithoutPrefix() => - Assert.Equal("[27] - Matilda \nCox - MARKETING", Badge.PrintLabel(null, "[27] - Matilda Cox - MARKETING", 15)); - - [Fact(Skip = "Remove this Skip property to run this test")] - public void PrintThreeLinesWithoutPrefix() => - Assert.Equal("[12] - Matilda \nLeanna Cox - EU\n MARKETING", Badge.PrintLabel("", "[12] - Matilda Leanna Cox - EU MARKETING", 15)); - - [Fact(Skip = "Remove this Skip property to run this test")] - public void PrintThreeLinesWithPrefix() => - Assert.Equal(" > [12] - Matilda \n > Leanna Cox - EU\n > MARKETING", Badge.PrintLabel(" > ", "[12] - Matilda Leanna Cox - EU MARKETING", 18)); + public void LabelForNewOwner() + { + Assert.Equal("Amare Osei - OWNER", Badge.Print(null, "Amare Osei", null)); + } } From 929bf4282015b8fd1ee6cb2555e114697a375256 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 29 Apr 2020 13:20:27 +0200 Subject: [PATCH 117/327] Remove unneeded class access modifier --- exercises/concept/basics/.docs/after.md | 8 +++----- exercises/concept/basics/.docs/introduction.md | 8 ++++---- exercises/concept/basics/.meta/Example.cs | 2 +- exercises/concept/basics/Basics.cs | 2 +- 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md index af35e7042f..65ad0e9fb0 100644 --- a/exercises/concept/basics/.docs/after.md +++ b/exercises/concept/basics/.docs/after.md @@ -15,12 +15,10 @@ count = 2; // Update to new value // count = false; ``` -C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. It is common to specify an _access modifier_, which influences what other classes can use the class. The most common access modifier is `public`, which means that other classes can use this class. - -A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Like classes, an access modifier can be specified for methods. Values are returned from functions using the [`return` keyword][return]. +C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from functions using the [`return` keyword][return]. To allow a method to be called by code in other files, the `public` access modifier must be added. ```csharp -public class Calculator +class Calculator { public int Add(int x, int y) { @@ -46,7 +44,7 @@ If the method to be called is defined in the same class as the method that calls If a method does not use any class _state_ (which is the case in this exercise), the method can be made _static_ using the `static` modifier. Similarly, if a class only has static methods, it too can be made static using the `static` modifier. ```csharp -public static class Calculator +static class Calculator { public static int Multiply(int x, int y) { diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/basics/.docs/introduction.md index bdba143fc6..7239f44996 100644 --- a/exercises/concept/basics/.docs/introduction.md +++ b/exercises/concept/basics/.docs/introduction.md @@ -15,19 +15,19 @@ count = 2; // Update to new value // count = false; ``` -C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. It is common to specify an _access modifier_, which influences what other classes can use the class. The most common access modifier is `public`, which means that other classes can use this class. +C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. ```csharp -public class Calculator +class Calculator { // ... } ``` -A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Like classes, an access modifier can be specified for methods. Values are returned from functions using the `return` keyword. +A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from functions using the `return` keyword. To allow a method to be called by code in other files, the `public` access modifier must be added. ```csharp -public class Calculator +class Calculator { public int Add(int x, int y) { diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/basics/.meta/Example.cs index 7617e1537d..554d34f6be 100644 --- a/exercises/concept/basics/.meta/Example.cs +++ b/exercises/concept/basics/.meta/Example.cs @@ -1,4 +1,4 @@ -public class Lasagna +class Lasagna { public int ExpectedMinutesInOven() { diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/basics/Basics.cs index f3b8b3bb01..b69283818f 100644 --- a/exercises/concept/basics/Basics.cs +++ b/exercises/concept/basics/Basics.cs @@ -1,4 +1,4 @@ -public class Lasagna +class Lasagna { // TODO: define the 'ExpectedMinutesInOven' method From df32d773a5cc042c842ce1af992da4598957a14c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 1 May 2020 14:33:37 +0200 Subject: [PATCH 118/327] Use consistent method references Use consistent method references Co-authored-by: wolf99 <281700+wolf99@users.noreply.github.com> --- exercises/concept/arrays/.docs/instructions.md | 2 +- exercises/concept/arrays/Arrays.cs | 10 +++++----- exercises/concept/basics/Basics.cs | 8 ++++---- exercises/concept/datetimes/.docs/instructions.md | 10 +++++----- exercises/concept/datetimes/DateTimes.cs | 10 +++++----- exercises/concept/enums/.docs/instructions.md | 4 ++-- exercises/concept/enums/Enums.cs | 6 +++--- exercises/concept/flag-enums/.docs/instructions.md | 8 ++++---- exercises/concept/flag-enums/FlagEnums.cs | 12 ++++++------ .../floating-point-numbers/.docs/instructions.md | 6 +++--- .../floating-point-numbers/FloatingPointNumbers.cs | 6 +++--- exercises/concept/nullability/.docs/instructions.md | 6 +++--- exercises/concept/nullability/Nullability.cs | 2 +- exercises/concept/numbers/.docs/instructions.md | 4 ++-- exercises/concept/numbers/Numbers.cs | 4 ++-- exercises/concept/strings/.docs/instructions.md | 6 +++--- exercises/concept/strings/Strings.cs | 6 +++--- reference/implementing-a-concept-exercise.md | 5 +++-- 18 files changed, 58 insertions(+), 57 deletions(-) diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md index 29c22d99eb..2a2794c18e 100644 --- a/exercises/concept/arrays/.docs/instructions.md +++ b/exercises/concept/arrays/.docs/instructions.md @@ -4,7 +4,7 @@ You have five tasks, all dealing with the numbers of birds that visited your gar ### 1. Check what the counts were last week -For comparison purposes, you always keep a copy of last week's counts nearby, which were: 0, 2, 5, 3, 7, 8 and 4. Implement the `BirdCount.LastWeek()` method that returns last week's counts: +For comparison purposes, you always keep a copy of last week's counts nearby, which were: 0, 2, 5, 3, 7, 8 and 4. Implement the (_static_) `BirdCount.LastWeek()` method that returns last week's counts: ```csharp BirdCount.LastWeek(); diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/arrays/Arrays.cs index 8522a323fb..c39cf2e8f1 100644 --- a/exercises/concept/arrays/Arrays.cs +++ b/exercises/concept/arrays/Arrays.cs @@ -11,26 +11,26 @@ public BirdCount(int[] birdsPerDay) public static int[] LastWeek() { - throw new NotImplementedException("Please implement the BirdCount.LastWeek method"); + throw new NotImplementedException("Please implement the (static) BirdCount.LastWeek() method"); } public int Yesterday() { - throw new NotImplementedException("Please implement the BirdCount.Yesterday method"); + throw new NotImplementedException("Please implement the BirdCount.Yesterday() method"); } public int Total() { - throw new NotImplementedException("Please implement the BirdCount.Total method"); + throw new NotImplementedException("Please implement the BirdCount.Total() method"); } public int BusyDays() { - throw new NotImplementedException("Please implement the BirdCount.BusyDays method"); + throw new NotImplementedException("Please implement the BirdCount.BusyDays() method"); } public bool HasDayWithoutBirds() { - throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds method"); + throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds() method"); } } diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/basics/Basics.cs index b69283818f..378ef7534a 100644 --- a/exercises/concept/basics/Basics.cs +++ b/exercises/concept/basics/Basics.cs @@ -1,10 +1,10 @@ class Lasagna { - // TODO: define the 'ExpectedMinutesInOven' method + // TODO: define the 'ExpectedMinutesInOven()' method - // TODO: define the 'RemainingMinutesInOven' method + // TODO: define the 'RemainingMinutesInOven()' method - // TODO: define the 'PreparationTimeInMinutes' method + // TODO: define the 'PreparationTimeInMinutes()' method - // TODO: define the 'TotalTimeInMinutes' method + // TODO: define the 'TotalTimeInMinutes()' method } diff --git a/exercises/concept/datetimes/.docs/instructions.md b/exercises/concept/datetimes/.docs/instructions.md index 531e60ef61..8fb319d19b 100644 --- a/exercises/concept/datetimes/.docs/instructions.md +++ b/exercises/concept/datetimes/.docs/instructions.md @@ -11,7 +11,7 @@ The tests will automatically set the culture to `en-US` - you don't have to set ### 1. Parse appointment date -Implement the `Appointment.Schedule()` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: +Implement the (_static_) `Appointment.Schedule()` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: ```csharp Appointment.Schedule("7/25/2019 13:45:00") @@ -20,7 +20,7 @@ Appointment.Schedule("7/25/2019 13:45:00") ### 2. Check if an appointment has already passed -Implement the `Appointment.HasPassed()` method that takes an appointment date and checks if the appointment was somewhere in the past: +Implement the (_static_) `Appointment.HasPassed()` method that takes an appointment date and checks if the appointment was somewhere in the past: ```csharp Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) @@ -29,7 +29,7 @@ Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) ### 3. Check if appointment is in the afternoon -Implement the `Appointment.IsAfternoonAppointment()` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): +Implement the (_static_) `Appointment.IsAfternoonAppointment()` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): ```csharp Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) @@ -38,7 +38,7 @@ Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) ### 4. Describe the time and date of the appointment -Implement the `Appointment.Description()` method that takes an appointment date and returns a description of that date and time: +Implement the (_static_) `Appointment.Description()` method that takes an appointment date and returns a description of that date and time: ```csharp Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) @@ -47,7 +47,7 @@ Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) ### 5. Return the anniversary date -Implement the `Appointment.AnniversaryDate()` method that returns this year's anniversary date, which is September 15th: +Implement the (_static_) `Appointment.AnniversaryDate()` method that returns this year's anniversary date, which is September 15th: ```csharp Appointment.AnniversaryDate() diff --git a/exercises/concept/datetimes/DateTimes.cs b/exercises/concept/datetimes/DateTimes.cs index 9b99d43e1a..d2f0983731 100644 --- a/exercises/concept/datetimes/DateTimes.cs +++ b/exercises/concept/datetimes/DateTimes.cs @@ -4,26 +4,26 @@ public static class Appointment { public static DateTime Schedule(string appointmentDateDescription) { - throw new NotImplementedException("Please implement the Appointment.Schedule method"); + throw new NotImplementedException("Please implement the (static) Appointment.Schedule() method"); } public static bool HasPassed(DateTime appointmentDate) { - throw new NotImplementedException("Please implement the Appointment.HasPassed method"); + throw new NotImplementedException("Please implement the (static) Appointment.HasPassed() method"); } public static bool IsAfternoonAppointment(DateTime appointmentDate) { - throw new NotImplementedException("Please implement the Appointment.IsAfternoonAppointment method"); + throw new NotImplementedException("Please implement the (static) Appointment.IsAfternoonAppointment() method"); } public static string Description(DateTime appointmentDate) { - throw new NotImplementedException("Please implement the Appointment.Description method"); + throw new NotImplementedException("Please implement the (static) Appointment.Description() method"); } public static DateTime AnniversaryDate() { - throw new NotImplementedException("Please implement the Appointment.AnniversaryDate method"); + throw new NotImplementedException("Please implement the (static) Appointment.AnniversaryDate() method"); } } diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index 180e054052..ff0b887eca 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -24,7 +24,7 @@ Define a `LogLevel` enum that has six elements corresponding to the above log le - `Error` - `Fatal` -Next, implement the `LogLine.ParseLogLevel()` method to parse the log level of a log line: +Next, implement the (_static_) `LogLine.ParseLogLevel()` method to parse the log level of a log line: ```csharp LogLine.ParseLogLevel("[INF]: File deleted") @@ -54,7 +54,7 @@ The encoded log level is simple mapping of a log level to a number: - `Fatal` - `7` - `Unknown` - `42` -Implement the `LogLine.OutputForShortLog()` method that can output the shortened log line format: +Implement the (_static_) `LogLine.OutputForShortLog()` method that can output the shortened log line format: ```csharp LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow") diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs index 2d5abe0bf8..1a43297de4 100644 --- a/exercises/concept/enums/Enums.cs +++ b/exercises/concept/enums/Enums.cs @@ -1,16 +1,16 @@ using System; -// TODO: define LogLevel enum +// TODO: define 'LogLevel' enum public static class LogLine { public static LogLevel ParseLogLevel(string logLine) { - throw new NotImplementedException("Please implement the LogLine.ParseLogLevel method"); + throw new NotImplementedException("Please implement the (static) LogLine.ParseLogLevel() method"); } public static string OutputForShortLog(LogLevel logLevel, string message) { - throw new NotImplementedException("Please implement the LogLine.OutputForShortLog method"); + throw new NotImplementedException("Please implement the (static) LogLine.OutputForShortLog() method"); } } diff --git a/exercises/concept/flag-enums/.docs/instructions.md b/exercises/concept/flag-enums/.docs/instructions.md index 2517485922..c42b862b34 100644 --- a/exercises/concept/flag-enums/.docs/instructions.md +++ b/exercises/concept/flag-enums/.docs/instructions.md @@ -18,7 +18,7 @@ You have four tasks. First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions. -Then implement the `Permissions.Default()` method to return the default permissions for a specific account type: +Then implement the (_static_) `Permissions.Default()` method to return the default permissions for a specific account type: ```csharp Permissions.Default(AccountType.Guest) @@ -27,7 +27,7 @@ Permissions.Default(AccountType.Guest) ### 2. Grant a permission -Implement the `Permissions.Grant()` method that grants (adds) a permission: +Implement the (_static_) `Permissions.Grant()` method that grants (adds) a permission: ```csharp Permissions.Grant(current: Permission.None, grant: Permission.Read) @@ -36,7 +36,7 @@ Permissions.Grant(current: Permission.None, grant: Permission.Read) ### 3. Revoke a permission -Implement the `Permissions.Revoke()` method that revokes (removes) a permission: +Implement the (_static_) `Permissions.Revoke()` method that revokes (removes) a permission: ```csharp Permissions.Revoke(current: Permission.Read, grant: Permission.Read) @@ -45,7 +45,7 @@ Permissions.Revoke(current: Permission.Read, grant: Permission.Read) ### 4. Check for a permission -Implement the `Permissions.Check()` method that takes the current account's permissions and checks if the account is authorized for a given permission: +Implement the (_static_) `Permissions.Check()` method that takes the current account's permissions and checks if the account is authorized for a given permission: ```csharp Permissions.Check(current: Permission.Write, check: Permission.Read) diff --git a/exercises/concept/flag-enums/FlagEnums.cs b/exercises/concept/flag-enums/FlagEnums.cs index f9a8599092..9a8df585b0 100644 --- a/exercises/concept/flag-enums/FlagEnums.cs +++ b/exercises/concept/flag-enums/FlagEnums.cs @@ -1,28 +1,28 @@ using System; -// TODO: define AccountType enum +// TODO: define 'AccountType' enum -// TODO: define Permission enum +// TODO: define 'Permission' enum public static class Permissions { public static Permission Default(AccountType accountType) { - throw new NotImplementedException("Please implement the Permissions.Default method"); + throw new NotImplementedException("Please implement the (static) Permissions.Default() method"); } public static Permission Grant(Permission current, Permission grant) { - throw new NotImplementedException("Please implement the Permissions.Grant method"); + throw new NotImplementedException("Please implement the (static) Permissions.Grant() method"); } public static Permission Revoke(Permission current, Permission revoke) { - throw new NotImplementedException("Please implement the Permissions.Revoke method"); + throw new NotImplementedException("Please implement the (static) Permissions.Revoke() method"); } public static bool Check(Permission current, Permission check) { - throw new NotImplementedException("Please implement the Permissions.Check method"); + throw new NotImplementedException("Please implement the (static) Permissions.Check() method"); } } diff --git a/exercises/concept/floating-point-numbers/.docs/instructions.md b/exercises/concept/floating-point-numbers/.docs/instructions.md index 62ff6a311f..c68bac30ea 100644 --- a/exercises/concept/floating-point-numbers/.docs/instructions.md +++ b/exercises/concept/floating-point-numbers/.docs/instructions.md @@ -9,7 +9,7 @@ You have three tasks, each of which will deal your balance and its interest rate ### 1. Calculate the interest rate -Implement the `SavingsAccount.InterestRate()` method to calculate the interest rate based on the specified balance: +Implement the (_static_) `SavingsAccount.InterestRate()` method to calculate the interest rate based on the specified balance: ```csharp SavingsAccount.InterestRate(balance: 200.75m) @@ -20,7 +20,7 @@ Note that the value returned is a `float`. ### 2. Calculate the annual balance update -Implement the `SavingsAccount.AnnualBalanceUpdate()` method to calculate the annual balance update, taking into account the interest rate: +Implement the (_static_) `SavingsAccount.AnnualBalanceUpdate()` method to calculate the annual balance update, taking into account the interest rate: ```csharp SavingsAccount.AnnualBalanceUpdate(balance: 200.75m) @@ -31,7 +31,7 @@ Note that the value returned is a `decimal`. ### 3. Calculate the years before reaching the desired balance -Implement the `SavingsAccount.YearsBeforeDesiredBalance()` method to calculate the minimum number of years required to reach the desired balance: +Implement the (_static_) `SavingsAccount.YearsBeforeDesiredBalance()` method to calculate the minimum number of years required to reach the desired balance: ```csharp SavingsAccount.YearsBeforeDesiredBalance(balance: 200.75m, targetBalance: 214.88m) diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs index 4247d08644..4f69aaefbe 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs @@ -4,16 +4,16 @@ public static class SavingsAccount { public static float InterestRate(decimal balance) { - throw new NotImplementedException("Please implement the SavingsAccount.InterestRate method"); + throw new NotImplementedException("Please implement the (static) SavingsAccount.InterestRate() method"); } public static decimal AnnualBalanceUpdate(decimal balance) { - throw new NotImplementedException("Please implement the SavingsAccount.AnnualBalanceUpdate method"); + throw new NotImplementedException("Please implement the (static) SavingsAccount.AnnualBalanceUpdate() method"); } public static int YearsBeforeDesiredBalance(decimal balance, decimal targetBalance) { - throw new NotImplementedException("Please implement the SavingsAccount.YearsBeforeDesiredBalance method"); + throw new NotImplementedException("Please implement the (static) SavingsAccount.YearsBeforeDesiredBalance() method"); } } diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/nullability/.docs/instructions.md index 59237543ba..e609dcea50 100644 --- a/exercises/concept/nullability/.docs/instructions.md +++ b/exercises/concept/nullability/.docs/instructions.md @@ -2,7 +2,7 @@ In this exercise you'll be writing code to print name badges for factory employe ### 1. Print a badge for an employee -Employees have an ID, name and department name. Employee badge labels are formatted as follows: `"[id] - [name] - [DEPARTMENT]"`. Implement the `Badge.Print()` method to return an employee's badge label: +Employees have an ID, name and department name. Employee badge labels are formatted as follows: `"[id] - [name] - [DEPARTMENT]"`. Implement the (_static_) `Badge.Print()` method to return an employee's badge label: ```csharp Badge.Print(734, "Ernest Johnny Payne", "Strategic Communication"); @@ -13,7 +13,7 @@ Note that the department should be uppercased on the label. ### 2. Print a badge for a new employee -Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory. As badges are required, they will receive a temporary badge without the ID prefix. Modify the `Badge.Print()` method to support new employees that don't yet have an ID: +Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory. As badges are required, they will receive a temporary badge without the ID prefix. Modify the (_static_) `Badge.Print()` method to support new employees that don't yet have an ID: ```csharp Badge.Print(id: null, "Jane Johnson", "Procurement"); @@ -22,7 +22,7 @@ Badge.Print(id: null, "Jane Johnson", "Procurement"); ### 3. Print a badge for the owner -Even the factory's owner has to wear a badge at all times. However, an owner does not have a department. In this case, the label should print `"OWNER"` instead of the department name. Modify the `Badge.Print()` method to print a label for the owner: +Even the factory's owner has to wear a badge at all times. However, an owner does not have a department. In this case, the label should print `"OWNER"` instead of the department name. Modify the (_static_) `Badge.Print()` method to print a label for the owner: ```csharp Badge.Print(254, "Charlotte Hale", department: null); diff --git a/exercises/concept/nullability/Nullability.cs b/exercises/concept/nullability/Nullability.cs index c6a058028e..f036b45907 100644 --- a/exercises/concept/nullability/Nullability.cs +++ b/exercises/concept/nullability/Nullability.cs @@ -4,6 +4,6 @@ public static class Badge { public static string Print(int? id, string name, string? department) { - throw new NotImplementedException("Please implement the Badge.Print method"); + throw new NotImplementedException("Please implement the (static) Badge.Print() method"); } } diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index 2d3f92bbf8..190d5dc4a1 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -11,7 +11,7 @@ You have two tasks. ### 1. Calculate the production rate per hour -Implement the `AssemblyLine.ProductionRatePerHour()` method to calculate the assembly line's production rate per hour, taking into account its success rate: +Implement the (_static_) `AssemblyLine.ProductionRatePerHour()` method to calculate the assembly line's production rate per hour, taking into account its success rate: ```csharp AssemblyLine.ProductionRatePerHour(6) @@ -22,7 +22,7 @@ Note that the value returned is a `double`. ### 2. Calculate the number of working items produced per minute -Implement the `AssemblyLine.WorkingItemsPerMinute()` method to calculate how many working cars are produced per minute: +Implement the (_static_) `AssemblyLine.WorkingItemsPerMinute()` method to calculate how many working cars are produced per minute: ```csharp AssemblyLine.WorkingItemsPerMinute(6) diff --git a/exercises/concept/numbers/Numbers.cs b/exercises/concept/numbers/Numbers.cs index 94487e5ae7..a5c8585c83 100644 --- a/exercises/concept/numbers/Numbers.cs +++ b/exercises/concept/numbers/Numbers.cs @@ -4,11 +4,11 @@ public static class AssemblyLine { public static double ProductionRatePerHour(int speed) { - throw new NotImplementedException("Please implement the AssemblyLine.ProductionRatePerHour method"); + throw new NotImplementedException("Please implement the (static) AssemblyLine.ProductionRatePerHour() method"); } public static int WorkingItemsPerMinute(int speed) { - throw new NotImplementedException("Please implement the AssemblyLine.WorkingItemsPerMinute method"); + throw new NotImplementedException("Please implement the (static) AssemblyLine.WorkingItemsPerMinute() method"); } } diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index 32ff33e09e..439d3dc55c 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -12,7 +12,7 @@ You have three tasks, each of which will take a log line and ask you to do somet ### 1. Get message from a log line -Implement the `LogLine.Message()` method to return a log line's message: +Implement the (_static_) `LogLine.Message()` method to return a log line's message: ```csharp LogLine.Message("[ERROR]: Invalid operation") @@ -28,7 +28,7 @@ LogLine.Message("[WARNING]: Disk almost full\r\n") ### 2. Get log level from a log line -Implement the `LogLine.LogLevel()` method to return a log line's log level, which should be returned in lowercase: +Implement the (_static_) `LogLine.LogLevel()` method to return a log line's log level, which should be returned in lowercase: ```csharp LogLine.LogLevel("[ERROR]: Invalid operation") @@ -37,7 +37,7 @@ LogLine.LogLevel("[ERROR]: Invalid operation") ### 3. Reformat a log line -Implement the `LogLine.Reformat()` method that reformats the log line, putting the message first and the log level after it in parentheses: +Implement the (_static_) `LogLine.Reformat()` method that reformats the log line, putting the message first and the log level after it in parentheses: ```csharp LogLine.Reformat("[INFO]: Operation completed") diff --git a/exercises/concept/strings/Strings.cs b/exercises/concept/strings/Strings.cs index d141880a0c..e8b543898a 100644 --- a/exercises/concept/strings/Strings.cs +++ b/exercises/concept/strings/Strings.cs @@ -4,16 +4,16 @@ public static class LogLine { public static string Message(string logLine) { - throw new NotImplementedException("Please implement the LogLine.Message method"); + throw new NotImplementedException("Please implement the (static) LogLine.Message() method"); } public static string LogLevel(string logLine) { - throw new NotImplementedException("Please implement the LogLine.LogLevel method"); + throw new NotImplementedException("Please implement the (static) LogLine.LogLevel() method"); } public static string Reformat(string logLine) { - throw new NotImplementedException("Please implement the LogLine.Reformat method"); + throw new NotImplementedException("Please implement the (static) LogLine.Reformat() method"); } } diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index a3b9bc9320..c1d3fd2f9d 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -51,7 +51,7 @@ The code files are track-specific and should be designed to help the student lea **Purpose:** Provide a stub implementation. - The stub implementation's code should compile. The only exception is for exercises that introduce syntax we _want_ a student to define themselves, like how to define a class or property. In this case, insert a descriptive TODO comment instead of providing stub code (see [this example][todo]). -- Stub methods should throw a `NotImplementedException` which message contains the method to implement (see [this example][not-implemented]). +- Stub methods should throw a `NotImplementedException` which message contains the method to implement, see [this instance method example][not-implemented]. The message is subtly different for static stub methods, see [this static method example][not-implemented-static]. For more information, please read [this in-depth description][stub-file], [watch this video][video-stub-file] and check [this example stub file][example-stub-file]. @@ -143,7 +143,8 @@ If you have any questions regarding implementing the exercise, please post them [example-project-file]: ../exercises/concept/strings/Strings.csproj [skip-fact]: ../exercises/concept/strings/StringsTests.cs#L11 [xunit]: https://xunit.net/ -[not-implemented]: ../exercises/concept/strings/Strings.cs#L5 +[not-implemented-static]: ../exercises/concept/arrays/Arrays.cs#L12 +[not-implemented]: ../exercises/concept/arrays/Arrays.cs#L17 [todo]: ../exercises/concept/basics/Basics.cs [stub-file]: ../../../docs/concept-exercises.md#stub-implementation-file [tests-file]: ../../../docs/concept-exercises.md#tests-file From 34683b188c33e7c2caad11077f214c0529a6a502 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 1 May 2020 14:33:55 +0200 Subject: [PATCH 119/327] Simplify classes Simplify classes --- exercises/concept/arrays/.meta/Example.cs | 2 +- exercises/concept/arrays/Arrays.cs | 2 +- exercises/concept/datetimes/.meta/Example.cs | 2 +- exercises/concept/datetimes/DateTimes.cs | 2 +- exercises/concept/enums/.docs/after.md | 4 ++-- exercises/concept/enums/.docs/introduction.md | 4 ++-- exercises/concept/enums/.meta/Example.cs | 4 ++-- exercises/concept/enums/Enums.cs | 2 +- exercises/concept/flag-enums/.docs/after.md | 10 +++++----- exercises/concept/flag-enums/.docs/introduction.md | 4 ++-- exercises/concept/flag-enums/.meta/Example.cs | 6 +++--- exercises/concept/flag-enums/FlagEnums.cs | 2 +- .../concept/floating-point-numbers/.meta/Example.cs | 2 +- .../floating-point-numbers/FloatingPointNumbers.cs | 2 +- exercises/concept/nullability/.meta/Example.cs | 2 +- exercises/concept/nullability/Nullability.cs | 2 +- exercises/concept/numbers/.meta/Example.cs | 2 +- exercises/concept/numbers/Numbers.cs | 2 +- exercises/concept/properties/.docs/after.md | 2 +- exercises/concept/properties/.meta/Example.cs | 6 +++--- exercises/concept/properties/Properties.cs | 6 +++--- exercises/concept/strings/.meta/Example.cs | 2 +- exercises/concept/strings/Strings.cs | 2 +- 23 files changed, 37 insertions(+), 37 deletions(-) diff --git a/exercises/concept/arrays/.meta/Example.cs b/exercises/concept/arrays/.meta/Example.cs index 0c4735e3ae..78e31c6788 100644 --- a/exercises/concept/arrays/.meta/Example.cs +++ b/exercises/concept/arrays/.meta/Example.cs @@ -1,6 +1,6 @@ using System; -public class BirdCount +class BirdCount { private int[] birdsPerDay; diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/arrays/Arrays.cs index c39cf2e8f1..d3cecb89af 100644 --- a/exercises/concept/arrays/Arrays.cs +++ b/exercises/concept/arrays/Arrays.cs @@ -1,6 +1,6 @@ using System; -public class BirdCount +class BirdCount { private int[] birdsPerDay; diff --git a/exercises/concept/datetimes/.meta/Example.cs b/exercises/concept/datetimes/.meta/Example.cs index 65f4a821a6..fee8d70195 100644 --- a/exercises/concept/datetimes/.meta/Example.cs +++ b/exercises/concept/datetimes/.meta/Example.cs @@ -1,6 +1,6 @@ using System; -public static class Appointment +static class Appointment { public static DateTime Schedule(string appointmentDateDescription) { diff --git a/exercises/concept/datetimes/DateTimes.cs b/exercises/concept/datetimes/DateTimes.cs index d2f0983731..bbd25f7f3b 100644 --- a/exercises/concept/datetimes/DateTimes.cs +++ b/exercises/concept/datetimes/DateTimes.cs @@ -1,6 +1,6 @@ using System; -public static class Appointment +static class Appointment { public static DateTime Schedule(string appointmentDateDescription) { diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md index 370f00ba89..fa2e10dc8a 100644 --- a/exercises/concept/enums/.docs/after.md +++ b/exercises/concept/enums/.docs/after.md @@ -3,7 +3,7 @@ You can use an enum whenever you have a fixed set of constant values. Using an e Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`. ```csharp -public enum Season +enum Season { Spring, // Value is 0 Summer = 2, // Value is 2 @@ -26,7 +26,7 @@ You should always consider using an enum whenever you want to model something as Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to any enum value: ```csharp -public enum Status +enum Status { Inactive = 0, Active = 1 diff --git a/exercises/concept/enums/.docs/introduction.md b/exercises/concept/enums/.docs/introduction.md index 6e93094ab0..9f383a26bb 100644 --- a/exercises/concept/enums/.docs/introduction.md +++ b/exercises/concept/enums/.docs/introduction.md @@ -1,7 +1,7 @@ The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows: ```csharp -public enum Season +enum Season { Spring, Summer, @@ -13,7 +13,7 @@ public enum Season If not defined explicitly, enum members will automatically get assigned incrementing integer values, with the first value being zero. It is also possible to assign values explicitly: ```csharp -public enum Answer +enum Answer { Maybe = 1, Yes = 3, diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/enums/.meta/Example.cs index e191810243..b1e68f43a7 100644 --- a/exercises/concept/enums/.meta/Example.cs +++ b/exercises/concept/enums/.meta/Example.cs @@ -1,4 +1,4 @@ -public enum LogLevel +enum LogLevel { Trace = 0, Debug = 1, @@ -9,7 +9,7 @@ public enum LogLevel Unknown = 42 } -public static class LogLine +static class LogLine { public static LogLevel ParseLogLevel(string logLine) { diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs index 1a43297de4..bb31ee7074 100644 --- a/exercises/concept/enums/Enums.cs +++ b/exercises/concept/enums/Enums.cs @@ -2,7 +2,7 @@ // TODO: define 'LogLevel' enum -public static class LogLine +static class LogLine { public static LogLevel ParseLogLevel(string logLine) { diff --git a/exercises/concept/flag-enums/.docs/after.md b/exercises/concept/flag-enums/.docs/after.md index df389cdc45..1307a79801 100644 --- a/exercises/concept/flag-enums/.docs/after.md +++ b/exercises/concept/flag-enums/.docs/after.md @@ -2,7 +2,7 @@ To allow a single enum instance to represent multiple values (usually referred t ```csharp [Flags] -public enum PhoneFeatures +enum PhoneFeatures { Call = 1, Text = 2 @@ -13,14 +13,14 @@ Besides using regular integers to set the flag enum members' values, one can als ```csharp [Flags] -public enum PhoneFeaturesBinary +enum PhoneFeaturesBinary { Call = 0b00000001, Text = 0b00000010 } [Flags] -public enum PhoneFeaturesBitwiseShift +enum PhoneFeaturesBitwiseShift { Call = 1 << 0, Text = 1 << 1 @@ -31,7 +31,7 @@ An enum member's value can refer to other enum members values: ```csharp [Flags] -public enum PhoneFeatures +enum PhoneFeatures { Call = 0b00000001, Text = 0b00000010, @@ -71,7 +71,7 @@ By default, the `int` type is used for enum member values. One can use a differe ```csharp [Flags] -public enum PhoneFeatures : byte +enum PhoneFeatures : byte { Call = 0b00000001, Text = 0b00000010 diff --git a/exercises/concept/flag-enums/.docs/introduction.md b/exercises/concept/flag-enums/.docs/introduction.md index 970c568943..8a354a7c6c 100644 --- a/exercises/concept/flag-enums/.docs/introduction.md +++ b/exercises/concept/flag-enums/.docs/introduction.md @@ -4,7 +4,7 @@ A flags enum can be defined as follows (using binary integer notation): ```csharp [Flags] -public enum PhoneFeatures +enum PhoneFeatures { Call = 0b00000001, Text = 0b00000010 @@ -33,7 +33,7 @@ By default, the `int` type is used for enum member values. One can use a differe ```csharp [Flags] -public enum PhoneFeatures : byte +enum PhoneFeatures : byte { Call = 0b00000001, Text = 0b00000010 diff --git a/exercises/concept/flag-enums/.meta/Example.cs b/exercises/concept/flag-enums/.meta/Example.cs index 720e8a460e..aba38be52f 100644 --- a/exercises/concept/flag-enums/.meta/Example.cs +++ b/exercises/concept/flag-enums/.meta/Example.cs @@ -1,6 +1,6 @@ using System; -public enum AccountType +enum AccountType { Guest, User, @@ -8,7 +8,7 @@ public enum AccountType } [Flags] -public enum Permission +enum Permission { None = 0b_0000_0000, Read = 0b_0000_0001, @@ -17,7 +17,7 @@ public enum Permission All = Read | Write | Delete } -public static class Permissions +static class Permissions { public static Permission Default(AccountType accountType) { diff --git a/exercises/concept/flag-enums/FlagEnums.cs b/exercises/concept/flag-enums/FlagEnums.cs index 9a8df585b0..243f9eab72 100644 --- a/exercises/concept/flag-enums/FlagEnums.cs +++ b/exercises/concept/flag-enums/FlagEnums.cs @@ -4,7 +4,7 @@ // TODO: define 'Permission' enum -public static class Permissions +static class Permissions { public static Permission Default(AccountType accountType) { diff --git a/exercises/concept/floating-point-numbers/.meta/Example.cs b/exercises/concept/floating-point-numbers/.meta/Example.cs index ea36426d02..0c588cd207 100644 --- a/exercises/concept/floating-point-numbers/.meta/Example.cs +++ b/exercises/concept/floating-point-numbers/.meta/Example.cs @@ -1,6 +1,6 @@ using System; -public static class SavingsAccount +static class SavingsAccount { public static float InterestRate(decimal balance) { diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs index 4f69aaefbe..959fba612f 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs @@ -1,6 +1,6 @@ using System; -public static class SavingsAccount +static class SavingsAccount { public static float InterestRate(decimal balance) { diff --git a/exercises/concept/nullability/.meta/Example.cs b/exercises/concept/nullability/.meta/Example.cs index 46997ead85..b745ffad9c 100644 --- a/exercises/concept/nullability/.meta/Example.cs +++ b/exercises/concept/nullability/.meta/Example.cs @@ -1,4 +1,4 @@ -public static class Badge +static class Badge { public static string Print(int? id, string name, string? department) { diff --git a/exercises/concept/nullability/Nullability.cs b/exercises/concept/nullability/Nullability.cs index f036b45907..2346758637 100644 --- a/exercises/concept/nullability/Nullability.cs +++ b/exercises/concept/nullability/Nullability.cs @@ -1,6 +1,6 @@ using System; -public static class Badge +static class Badge { public static string Print(int? id, string name, string? department) { diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/numbers/.meta/Example.cs index 5d9613b8c4..bdae2967b0 100644 --- a/exercises/concept/numbers/.meta/Example.cs +++ b/exercises/concept/numbers/.meta/Example.cs @@ -1,4 +1,4 @@ -public static class AssemblyLine +static class AssemblyLine { private const int ProductionRatePerHourForDefaultSpeed = 221; diff --git a/exercises/concept/numbers/Numbers.cs b/exercises/concept/numbers/Numbers.cs index a5c8585c83..0f864f489a 100644 --- a/exercises/concept/numbers/Numbers.cs +++ b/exercises/concept/numbers/Numbers.cs @@ -1,6 +1,6 @@ using System; -public static class AssemblyLine +static class AssemblyLine { public static double ProductionRatePerHour(int speed) { diff --git a/exercises/concept/properties/.docs/after.md b/exercises/concept/properties/.docs/after.md index 8262879468..7882cf52a1 100644 --- a/exercises/concept/properties/.docs/after.md +++ b/exercises/concept/properties/.docs/after.md @@ -59,7 +59,7 @@ the set accessor may be ommitted completely. This is maybe because the value of the property is set in the class's constructor. ```csharp -public class MyClass +class MyClass { public MyClass( int importantValue) { diff --git a/exercises/concept/properties/.meta/Example.cs b/exercises/concept/properties/.meta/Example.cs index 0b78e3a447..03ca66c52a 100644 --- a/exercises/concept/properties/.meta/Example.cs +++ b/exercises/concept/properties/.meta/Example.cs @@ -1,12 +1,12 @@ using System; -public enum Units +enum Units { Pounds, Kilograms } -public class WeighingMachine +class WeighingMachine { private const decimal POUNDS_PER_KILOGRAM = 2.20462m; private decimal inputWeight; @@ -49,7 +49,7 @@ public USWeight USDisplayWeight private decimal WeightInPounds(decimal weight) => Units == Units.Kilograms ? weight * POUNDS_PER_KILOGRAM : weight; } -public class USWeight +class USWeight { private const decimal OUNCES_PER_POUND = 16m; diff --git a/exercises/concept/properties/Properties.cs b/exercises/concept/properties/Properties.cs index abdaad50fb..d6160fb536 100644 --- a/exercises/concept/properties/Properties.cs +++ b/exercises/concept/properties/Properties.cs @@ -1,12 +1,12 @@ using System; -public enum Units +enum Units { Pounds, Kilograms } -public class WeighingMachine +class WeighingMachine { // TODO: define the 'InputWeight' property @@ -19,7 +19,7 @@ public class WeighingMachine // TODO: define the 'Units' property } -public struct USWeight +struct USWeight { public USWeight(decimal weightInPounds) { diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs index 626096324d..d140439625 100644 --- a/exercises/concept/strings/.meta/Example.cs +++ b/exercises/concept/strings/.meta/Example.cs @@ -1,4 +1,4 @@ -public static class LogLine +static class LogLine { public static string Message(string logLine) { diff --git a/exercises/concept/strings/Strings.cs b/exercises/concept/strings/Strings.cs index e8b543898a..48396c5a22 100644 --- a/exercises/concept/strings/Strings.cs +++ b/exercises/concept/strings/Strings.cs @@ -1,6 +1,6 @@ using System; -public static class LogLine +static class LogLine { public static string Message(string logLine) { From 821398075e770250b9cfd2babf2ab8174204c7eb Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 2 May 2020 13:27:05 +0200 Subject: [PATCH 120/327] Add classes exercise Add classes exercise Co-authored-by: Jeremy Walker Co-authored-by: wolf99 <281700+wolf99@users.noreply.github.com> --- exercises/concept/classes/.docs/after.md | 100 ++++++++++++++++ exercises/concept/classes/.docs/hints.md | 35 ++++++ .../concept/classes/.docs/instructions.md | 81 +++++++++++++ .../concept/classes/.docs/introduction.md | 66 +++++++++++ exercises/concept/classes/.meta/Example.cs | 34 ++++++ exercises/concept/classes/.meta/config.json | 8 ++ exercises/concept/classes/.meta/design.md | 54 +++++++++ exercises/concept/classes/Classes.cs | 24 ++++ exercises/concept/classes/Classes.csproj | 13 +++ exercises/concept/classes/ClassesTests.cs | 109 ++++++++++++++++++ 10 files changed, 524 insertions(+) create mode 100644 exercises/concept/classes/.docs/after.md create mode 100644 exercises/concept/classes/.docs/hints.md create mode 100644 exercises/concept/classes/.docs/instructions.md create mode 100644 exercises/concept/classes/.docs/introduction.md create mode 100644 exercises/concept/classes/.meta/Example.cs create mode 100644 exercises/concept/classes/.meta/config.json create mode 100644 exercises/concept/classes/.meta/design.md create mode 100644 exercises/concept/classes/Classes.cs create mode 100644 exercises/concept/classes/Classes.csproj create mode 100644 exercises/concept/classes/ClassesTests.cs diff --git a/exercises/concept/classes/.docs/after.md b/exercises/concept/classes/.docs/after.md new file mode 100644 index 0000000000..acb0ef4333 --- /dev/null +++ b/exercises/concept/classes/.docs/after.md @@ -0,0 +1,100 @@ +The primary object-oriented construct in C# is the _class_, which is a combination of data ([_fields_][fields]) and behavior ([_methods_][methods]). The fields and methods of a class are known as its _members_. + +Access to members can be restricted through access modifiers, the two most common ones being: + +- [`public`][public]: the member can be accessed by any code (no restrictions). +- [`private`][private]: the member can only be accessed by code in the same class. + +It is customary to specify an access modifier for all members. If no access modifier is specified, it will default to `private`. + +The above-mentioned grouping of related data and behavior plus restricting access to members is known as _encapsulation_, which is one of the core object-oriented concepts. + +You can think of a class as a template for creating instances of that class. To [create an instance of a class][creating-objects] (also known as an _object_), the [`new` keyword][new] is used: + +```csharp +class Car +{ +} + +// Create two car instances +var myCar = new Car(); +var yourCar = new Car(); +``` + +[Fields][fields] have a type and a name (defined in [camelCase][camel-case]) and can be defined anywhere in a class (defined in [PascalCase][pascal-case]). + +```csharp +class Car +{ + // Accessible by anyone + public int weight; + + // Only accessible by code in this class + private string color; +} +``` + +One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it wll be set to its type's [default value][default-values]. An instance's field values can be accessed and updated using dot-notation. + +```csharp +class Car +{ + // Will be set to specified value + public int weight = 2500; + + // Will be set to default value (0) + public int year; +} + +var newCar = new Car(); +newCar.weight; // => 2500 +newCar.year; // => 0 + +// Update value of the field +newCar.year = 2018; +``` + +Private fields are usually updated as a side-effect of calling a method. Such methods usually don't return any value, in which case the return type should be [`void`][void]: + +```csharp +class CarImporter +{ + private int carsImported; + + public void ImportCars(int numberOfCars) + { + // Update private field + carsImported = carsImported + numberOfCars; + } +} +``` + +Note that is not customary to use public fields in C# classes. Either private fields are used or other types of members that will be discussed in subsequent exercises. + +Within a class, the [`this` keyword][this] will refer to the current class. This is especially useful if a parameter has the same name as a field: + +```csharp +class CarImporter +{ + private int carsImported; + + public void SetImportedCars(int carsImported) + { + // Update private field from public method + this.carsImported = carsImported; + } +} +``` + +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods +[this]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this +[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator +[void]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/void +[creating-objects]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#creating-objects +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[public]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/public +[private]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private +[default-values]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values +[camel-case]: https://techterms.com/definition/camelcase +[pascal-case]: https://techterms.com/definition/pascalcase diff --git a/exercises/concept/classes/.docs/hints.md b/exercises/concept/classes/.docs/hints.md new file mode 100644 index 0000000000..ba4002abad --- /dev/null +++ b/exercises/concept/classes/.docs/hints.md @@ -0,0 +1,35 @@ +### General + +### 1. Buy a brand-new remote controlled car + +- [This page shows how to create a new instance of a class][creating-objects]. + +### 2. Display the distance driven + +- Keep track of the distance driven in a [field][fields]. +- Consider what visibility to use for the field (does it need to be used outside the class?). +- Consider using [string interpolation][string-interpolation] to format the string to return. + +### 3. Display the battery percentage + +- Keep track of the distance driven in a [field][fields]. +- Initialize the field to a specific value to correspond to the initial battery charge. +- Consider what visibility to use for the field (does it need to be used outside the class?). +- Consider using [string interpolation][string-interpolation] to format the string to return. + +### 4. Update the number of meters driven when driving + +- Update the field representing the distance driven. + +### 5. Update the battery percentage when driving + +- Update the field representing the battery percentage driven. + +### 6. Prevent driving when the battery is drained + +- Add a conditional to only update the distance and battery if the battery is not already drained. +- Add a conditional to display the empty battery message if the battery is drained. + +[creating-objects]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#creating-objects +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[string-interpolation]: https://christianfindlay.com/2019/10/04/c-string-interpolation/ diff --git a/exercises/concept/classes/.docs/instructions.md b/exercises/concept/classes/.docs/instructions.md new file mode 100644 index 0000000000..19f281834b --- /dev/null +++ b/exercises/concept/classes/.docs/instructions.md @@ -0,0 +1,81 @@ +In this exercise you'll be playing around with a remote controlled car, which you've finally saved enough money for to buy. + +Cars start with full (100%) batteries. Each time you drive the car using the remote control, it covers 20 meters and drains one percent of the battery. + +The remote controlled car has a fancy LED display that shows two bits of information: + +- The total distance it has driven, displayed as: `"Driven meters"`. +- The remaining battery charge, displayed as: `"Battery at %"`. + +If the battery is at 0%, you can't drive the car anymore and the battery display will show `"Battery empty"`. + +You have six tasks, each of which will work with remote controlled car instances. + +### 1. Buy a brand-new remote controlled car + +Implement the (_static_) `RemoteControlCar.Buy()` method to return a brand-new remote controlled car instance: + +```csharp +RemoteControlCar car = RemoteControlCar.Buy(); +``` + +### 2. Display the distance driven + +Implement the `RemoteControlCar.DistanceDisplay()` method to return the distance as displayed on the LED display: + +```csharp +var car = RemoteControlCar.Buy(); +car.DistanceDisplay(); +// => "Driven 0 meters" +``` + +### 3. Display the battery percentage + +Implement the `RemoteControlCar.BatteryDisplay()` method to return the distance as displayed on the LED display: + +```csharp +var car = RemoteControlCar.Buy(); +car.BatteryDisplay(); +// => "Battery at 100%" +``` + +### 4. Update the number of meters driven when driving + +Implement the `RemoteControlCar.Drive()` method that updates the number of meters driven: + +```csharp +var car = RemoteControlCar.Buy(); +car.Drive(); +car.Drive(); +car.DistanceDisplay(); +// => "Driven 40 meters" +``` + +### 5. Update the battery percentage when driving + +Update the `RemoteControlCar.Drive()` method to update the battery percentage: + +```csharp +var car = RemoteControlCar.Buy(); +car.Drive(); +car.Drive(); +car.BatteryDisplay(); +// => "Battery at 98%" +``` + +### 6. Prevent driving when the battery is drained + +Update the `RemoteControlCar.Drive()` method to not increase the distance driven nor decrease the battery percentage when the battery is drained (at 0%): + +```csharp +var car = RemoteControlCar.Buy(); + +// Drain the battery +// ... + +car.DistanceDisplay(); +// => "Driven 2000 meters" + +car.BatteryDisplay(); +// => "Battery empty" +``` diff --git a/exercises/concept/classes/.docs/introduction.md b/exercises/concept/classes/.docs/introduction.md new file mode 100644 index 0000000000..e3770a9229 --- /dev/null +++ b/exercises/concept/classes/.docs/introduction.md @@ -0,0 +1,66 @@ +The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_. + +Access to members can be restricted through access modifiers, the two most common ones being: + +- `public`: the member can be accessed by any code (no restrictions). +- `private`: the member can only be accessed by code in the same class. + +You can think of a class as a template for creating instances of that class. To create an instance of a class (also known as an _object_), the `new` keyword is used: + +```csharp +class Car +{ +} + +// Create two car instances +var myCar = new Car(); +var yourCar = new Car(); +``` + +Fields have a type and a name (defined in camelCase) and can be defined anywhere in a class (defined in PascalCase): + +```csharp +class Car +{ + // Accessible by anyone + public int weight; + + // Only accessible by code in this class + private string color; +} +``` + +One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it wll be set to its type's default value. An instance's field values can be accessed and updated using dot-notation. + +```csharp +class Car +{ + // Will be set to specified value + public int weight = 2500; + + // Will be set to default value (0) + public int year; +} + +var newCar = new Car(); +newCar.weight; // => 2500 +newCar.year; // => 0 + +// Update value of the field +newCar.year = 2018; +``` + +Private fields are usually updated as a side-effect of calling a method. Such methods usually don't return any value, in which case the return type should be `void`: + +```csharp +class CarImporter +{ + private int carsImported; + + public void ImportCars(int numberOfCars) + { + // Update private field from public method + carsImported = carsImported + numberOfCars; + } +} +``` diff --git a/exercises/concept/classes/.meta/Example.cs b/exercises/concept/classes/.meta/Example.cs new file mode 100644 index 0000000000..96dd270e51 --- /dev/null +++ b/exercises/concept/classes/.meta/Example.cs @@ -0,0 +1,34 @@ +class RemoteControlCar +{ + private int batteryPercentage = 100; + private int distanceDrivenInMeters = 0; + + public void Drive() + { + if (batteryPercentage > 0) + { + batteryPercentage--; + distanceDrivenInMeters += 20; + } + } + + public string DistanceDisplay() + { + return $"Driven {distanceDrivenInMeters} meters"; + } + + public string BatteryDisplay() + { + if (batteryPercentage == 0) + { + return "Battery empty"; + } + + return $"Battery at {batteryPercentage}%"; + } + + public static RemoteControlCar Buy() + { + return new RemoteControlCar(); + } +} diff --git a/exercises/concept/classes/.meta/config.json b/exercises/concept/classes/.meta/config.json new file mode 100644 index 0000000000..6d4e44d872 --- /dev/null +++ b/exercises/concept/classes/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md new file mode 100644 index 0000000000..d28eb69745 --- /dev/null +++ b/exercises/concept/classes/.meta/design.md @@ -0,0 +1,54 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the Concept of Classes in C#. + +## Learning objectives + +- Know what classes are. +- Know what encapsulation is. +- Know what fields are. +- Know how to create an object. +- Know how to update state through methods. +- Know about the `void` type. + +## Out of scope + +- Reference equality. +- Reference parameter passing. +- Constructors. +- Interfaces. +- Inheritance. +- Properties. +- Indexers. +- Structs. +- Destructors. +- Method overloading. +- Pattern matching. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `classes`: know what classes are; know what encapsulation is; know what fields are; know how to create an object; know how to update state through methods; know about the `void` type. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `basics`: know how to define a basic class with basic methods. +- `strings`: know how to do basic string interpolation. +- `numbers`: know how to compare numbers. +- `conditionals`: know how to do conditional logic. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/classes/Classes.cs b/exercises/concept/classes/Classes.cs new file mode 100644 index 0000000000..9a88a3543a --- /dev/null +++ b/exercises/concept/classes/Classes.cs @@ -0,0 +1,24 @@ +using System; + +class RemoteControlCar +{ + public static RemoteControlCar Buy() + { + throw new NotImplementedException("Please implement the (static) RemoteControlCar.Buy() method"); + } + + public string DistanceDisplay() + { + throw new NotImplementedException("Please implement the RemoteControlCar.DistanceDisplay() method"); + } + + public string BatteryDisplay() + { + throw new NotImplementedException("Please implement the RemoteControlCar.BatteryDisplay() method"); + } + + public void Drive() + { + throw new NotImplementedException("Please implement the RemoteControlCar.Drive() method"); + } +} diff --git a/exercises/concept/classes/Classes.csproj b/exercises/concept/classes/Classes.csproj new file mode 100644 index 0000000000..8d66e73a50 --- /dev/null +++ b/exercises/concept/classes/Classes.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/classes/ClassesTests.cs b/exercises/concept/classes/ClassesTests.cs new file mode 100644 index 0000000000..e10443a57d --- /dev/null +++ b/exercises/concept/classes/ClassesTests.cs @@ -0,0 +1,109 @@ +using Xunit; + +public class RemoteControlCarTests +{ + [Fact] + public void BuyNewCarReturnsInstance() + { + var car = RemoteControlCar.Buy(); + Assert.NotNull(car); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BuyNewCarReturnsNewCarEachTime() + { + var car1 = RemoteControlCar.Buy(); + var car2 = RemoteControlCar.Buy(); + Assert.NotSame(car2, car1); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NewCarDistanceDisplay() + { + var car = new RemoteControlCar(); + Assert.Equal("Driven 0 meters", car.DistanceDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NewCarBatteryDisplay() + { + var car = new RemoteControlCar(); + Assert.Equal("Battery at 100%", car.BatteryDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DistanceDisplayAfterDrivingOnce() + { + var car = new RemoteControlCar(); + car.Drive(); + Assert.Equal("Driven 20 meters", car.DistanceDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DistanceDisplayAfterDrivingMultipleTimes() + { + var car = new RemoteControlCar(); + + for (var i = 0; i < 17; i++) + { + car.Drive(); + } + + Assert.Equal("Driven 340 meters", car.DistanceDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BatteryDisplayAfterDrivingOnce() + { + var car = new RemoteControlCar(); + car.Drive(); + Assert.Equal("Battery at 99%", car.BatteryDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BatteryDisplayAfterDrivingMultipleTimes() + { + var car = new RemoteControlCar(); + + for (var i = 0; i < 23; i++) + { + car.Drive(); + } + + Assert.Equal("Battery at 77%", car.BatteryDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BatteryDisplayWhenBatteryEmpty() + { + var car = new RemoteControlCar(); + + // Drain the battery + for (var i = 0; i < 100; i++) + { + car.Drive(); + } + + // Attempt to drive one more time (should not work) + car.Drive(); + + Assert.Equal("Battery empty", car.BatteryDisplay()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DistanceDisplayWhenBatteryEmpty() + { + var car = new RemoteControlCar(); + + // Drain the battery + for (var i = 0; i < 100; i++) + { + car.Drive(); + } + + // Attempt to drive one more time (should not work) + car.Drive(); + + Assert.Equal("Driven 2000 meters", car.DistanceDisplay()); + } +} From 0a7bca85fd235da5867b597ca896fc7a0d5bbb5d Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 6 May 2020 11:58:16 +0200 Subject: [PATCH 121/327] Use consistent todo text --- exercises/concept/enums/Enums.cs | 2 +- exercises/concept/flag-enums/FlagEnums.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/enums/Enums.cs index bb31ee7074..3c0433e00c 100644 --- a/exercises/concept/enums/Enums.cs +++ b/exercises/concept/enums/Enums.cs @@ -1,6 +1,6 @@ using System; -// TODO: define 'LogLevel' enum +// TODO: define the 'LogLevel' enum static class LogLine { diff --git a/exercises/concept/flag-enums/FlagEnums.cs b/exercises/concept/flag-enums/FlagEnums.cs index 243f9eab72..8a4b86bce8 100644 --- a/exercises/concept/flag-enums/FlagEnums.cs +++ b/exercises/concept/flag-enums/FlagEnums.cs @@ -1,8 +1,8 @@ using System; -// TODO: define 'AccountType' enum +// TODO: define the 'AccountType' enum -// TODO: define 'Permission' enum +// TODO: define the 'Permission' enum static class Permissions { From bcfc1aadec42905414412fc3d202a40fb25fcb3b Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 7 May 2020 09:22:58 +0200 Subject: [PATCH 122/327] Add constructors exercise Add constructors exercise Co-authored-by: github-actions[bot] Co-authored-by: Rob Keim --- exercises/concept/constructors/.docs/after.md | 73 +++++++ exercises/concept/constructors/.docs/hints.md | 36 ++++ .../constructors/.docs/instructions.md | 81 ++++++++ .../constructors/.docs/introduction.md | 36 ++++ .../concept/constructors/.meta/Example.cs | 57 ++++++ .../concept/constructors/.meta/config.json | 8 + .../concept/constructors/.meta/design.md | 44 +++++ .../concept/constructors/Constructors.cs | 36 ++++ .../concept/constructors/Constructors.csproj | 13 ++ .../concept/constructors/ConstructorsTests.cs | 181 ++++++++++++++++++ 10 files changed, 565 insertions(+) create mode 100644 exercises/concept/constructors/.docs/after.md create mode 100644 exercises/concept/constructors/.docs/hints.md create mode 100644 exercises/concept/constructors/.docs/instructions.md create mode 100644 exercises/concept/constructors/.docs/introduction.md create mode 100644 exercises/concept/constructors/.meta/Example.cs create mode 100644 exercises/concept/constructors/.meta/config.json create mode 100644 exercises/concept/constructors/.meta/design.md create mode 100644 exercises/concept/constructors/Constructors.cs create mode 100644 exercises/concept/constructors/Constructors.csproj create mode 100644 exercises/concept/constructors/ConstructorsTests.cs diff --git a/exercises/concept/constructors/.docs/after.md b/exercises/concept/constructors/.docs/after.md new file mode 100644 index 0000000000..ca5bb2aeda --- /dev/null +++ b/exercises/concept/constructors/.docs/after.md @@ -0,0 +1,73 @@ +Creating an instance of a _class_ is done by calling its [_constructor_][constructors] through the [`new` operator][new]. A constructor is a special type of method whose goal is to initialize a newly created instance. [Constructors look like regular methods][constructor-syntax], but without a return type and with a name that matches the classes' name. + +```csharp +class Library +{ + private books; + + public Library() + { + this.books = 10; + } +} + +// This will call the constructor +var library = new Library(); +``` + +Like regular methods, constructors can have parameters. Constructor parameters are usually stored as (private) [fields][fields] to be accessed later, or else used in some one-off calculation. Arguments can be passed to constructors just like passing arguments to regular methods. + +```csharp +class Building +{ + private int numberOfStories; + private int totalHeight; + + public Building(int numberOfStories, double storyHeight) + { + this.numberOfStories = numberOfStories; + this.totalHeight = numberOfStories * storyHeight; + } +} + +// Call a constructor with two arguments +var largeBuilding = new Building(55, 6.2) +``` + +Specifying a constructor is optional. If no constructor is specified, a [parameterless constructor][parameterless-constructors] is generated by the compiler: + +```csharp +class Elevator +{ +} + +// This will call the (empty) generated constructor +var elevator = new Elevator(); +``` + +If fields have an initial value assigned to them, the compiler will output code in which the assignment is actually done inside the constructor. The following class declarations are thus equivalent (functionality-wise): + +```csharp +class UsingFieldInitialization +{ + private int players = 5; +} + +class UsingConstructorInitialization +{ + private int players; + + public UsingConstructorInitialization() + { + players = 5; + } +} +``` + +[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors +[constructor-syntax]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax +[using-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors +[private-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/private-constructors +[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[parameterless-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#parameterless-constructors diff --git a/exercises/concept/constructors/.docs/hints.md b/exercises/concept/constructors/.docs/hints.md new file mode 100644 index 0000000000..2eb06954fd --- /dev/null +++ b/exercises/concept/constructors/.docs/hints.md @@ -0,0 +1,36 @@ +### 1. Creating a remote controlled car + +- [Define a constructor][constructor-syntax] that has two `int` parameters. +- Store the two parameters as [fields][fields] to access them from the classes' methods. + +### 2. Creating a race track + +- [Define a constructor][constructor-syntax] that has one `int` parameter. +- Store the parameter as a [field][fields] to access it from the class' method. + +### 3. Drive the car + +- Add a [field][fields] to keep track of the distance driven. +- Add the car's speed to the [field][fields] that keeps track of the distance driven. + +### 4. Check for a drained battery + +- Add a [field][fields] to keep track of the remaining battery charge percentage (starts at 100%). +- Remove the car's battery drain from the [field][fields] to keep track of the battery charge. +- Don't update the distance driven if the battery is drained. +- Remember that if the battery charge is less than the battery drain percentage, it is considered drained. + +### 5. Create the Nitro remote control car + +- [Instantiate][instance-constructors] an instance of the `RemoteControlCar` with the correct arguments. + +### 6. Check if a remote control car can finish a race + +- Solving this is probably best done by [repeatedly driving the car][while]. +- Remember that the car has a method to retrieve the distance it has driven. +- Consider what to do when the battery has been drained before reaching the finish line. + +[constructor-syntax]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax +[instance-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors +[while]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/while +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields diff --git a/exercises/concept/constructors/.docs/instructions.md b/exercises/concept/constructors/.docs/instructions.md new file mode 100644 index 0000000000..f591384849 --- /dev/null +++ b/exercises/concept/constructors/.docs/instructions.md @@ -0,0 +1,81 @@ +In this exercise you'll be organizing races between various types of remote controlled cars. Each car has its own speed and battery drain characteristics. + +Cars start with full (100%) batteries. Each time you drive the car using the remote control, it covers the car's speed in meters and decreases the remaining battery percentage by its battery drain. + +If a car's battery is below its battery drain percentage, you can't drive the car anymore. + +Each race track has its own distance. Cars are tested by checking if they can finish the track without running out of battery. + +You have six tasks, each of which will work with remote controller car instances. + +### 1. Creating a remote controlled car + +Allow creating a remote controller car by defining a constructor for the `RemoteControlCar` class that takes the speed of the car in meters and the battery drain percentage as its two parameters (both of type `int`): + +```csharp +int speed = 5; +int batteryDrain = 2; +var car = new RemoteControlCar(speed, batteryDrain); +``` + +### 2. Creating a race track + +Allow creating a race track by defining a constructor for the `RaceTrack` class that takes the track's distance in meters as its sole parameter (which is of type `int`): + +```csharp +int distance = 800; +var raceTrack = new RaceTrack(distance); +``` + +### 3. Drive the car + +Implement the `RemoteControlCar.Drive()` method that updates the number of meters driven based on the car's speed. Also implement the `RemoteControlCar.DistanceDriven()` method to return the number of meters driven by the car: + +```csharp +int speed = 5; +int batteryDrain = 2; +var car = new RemoteControlCar(speed, batteryDrain); +car.Drive(); + +car.DistanceDriven(); +// => 5 +``` + +### 4. Check for a drained battery + +Update the `RemoteControlCar.Drive()` method to drain the battery based on the car's battery drain. Also implement the `RemoteControlCar.BatteryDrained()` method that indicates if the battery is drained: + +```csharp +int speed = 5; +int batteryDrain = 2; +var car = new RemoteControlCar(speed, batteryDrain); +car.Drive(); + +car.BatteryDrained(); +// => false +``` + +### 5. Create the Nitro remote control car + +The best-selling remote control car is the Nitro, which has a stunning top speed of 50 meters with a battery drain of 4%. Implement the (static) `RemoteControlCar.Nitro()` method to return this type of car: + +````csharp +var car = RemoteControlCar.Nitro(); +car.Drive(); +car.DistanceDriven(); +// => 50 +### 6. Check if a remote control car can finish a race + +To finish a race, a car has to be able to drive the race's distance. This means not draining its battery before having crossed the finish line. Implement the `Race.CarCanFinish()` method that takes a `RemoteControlCar` instance as its parameter and returns `true` if the car can finish the race; otherwise, return `false`: + +```csharp +int speed = 5; +int batteryDrain = 2; +var car = new RemoteControlCar(speed, batteryDrain); + +int distance = 100; +var race = new Race(distance); + +race.CarCanFinish(car); +// => true +```` diff --git a/exercises/concept/constructors/.docs/introduction.md b/exercises/concept/constructors/.docs/introduction.md new file mode 100644 index 0000000000..1fbd17c9ef --- /dev/null +++ b/exercises/concept/constructors/.docs/introduction.md @@ -0,0 +1,36 @@ +Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name. + +```csharp +class Library +{ + private books; + + public Library() + { + // Initialize the books field + this.books = 10; + } +} + +// This will call the constructor +var library = new Library(); +``` + +Like regular methods, constructors can have parameters. Constructor parameters are usually stored as (private) fields to be accessed later, or else used in some one-off calculation. Arguments can be passed to constructors just like passing arguments to regular methods. + +```csharp +class Building +{ + private int numberOfStories; + private int totalHeight; + + public Building(int numberOfStories, double storyHeight) + { + this.numberOfStories = numberOfStories; + this.totalHeight = numberOfStories * storyHeight; + } +} + +// Call a constructor with two arguments +var largeBuilding = new Building(55, 6.2) +``` diff --git a/exercises/concept/constructors/.meta/Example.cs b/exercises/concept/constructors/.meta/Example.cs new file mode 100644 index 0000000000..a472628ab2 --- /dev/null +++ b/exercises/concept/constructors/.meta/Example.cs @@ -0,0 +1,57 @@ +class RemoteControlCar +{ + private int speed; + private int battery = 100; + private int batteryDrain; + private int distance; + + public RemoteControlCar(int speed, int batteryDrain) + { + this.speed = speed; + this.batteryDrain = batteryDrain; + } + + public bool BatteryDrained() + { + return battery < batteryDrain; + } + + public int DistanceDriven() + { + return distance; + } + + public void Drive() + { + if (!BatteryDrained()) + { + battery -= batteryDrain; + distance += speed; + } + } + + public static RemoteControlCar TopOfTheLine() + { + return new RemoteControlCar(50, 4); + } +} + +class RaceTrack +{ + private int distance; + + public RaceTrack(int distance) + { + this.distance = distance; + } + + public bool CarCanFinish(RemoteControlCar car) + { + while (!car.BatteryDrained()) + { + car.Drive(); + } + + return car.DistanceDriven() >= distance; + } +} diff --git a/exercises/concept/constructors/.meta/config.json b/exercises/concept/constructors/.meta/config.json new file mode 100644 index 0000000000..6d4e44d872 --- /dev/null +++ b/exercises/concept/constructors/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md new file mode 100644 index 0000000000..d368b24492 --- /dev/null +++ b/exercises/concept/constructors/.meta/design.md @@ -0,0 +1,44 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the Concept of Constructors in C#. + +## Learning objectives + +- Know what constructors are +- Know how to define parameterless constructors +- Know how to define parameterized constructors + +## Out of scope + +- Constructor overloading +- Private constructors +- Static constructors +- Destructors + +## Concepts + +This Concepts Exercise's Concepts are: + +- `constructors`: know what constructors are; know how to define parameterless constructors; know how to define parameterized constructors; know how to use constructor overloading; know how to define private constructors. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `classes`: know how to work with classes. +- `numbers`: know how compare numbers. +- `conditionals`: know how to do conditional logic. +- `while-loops`: know how to use `while` loops. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/constructors/Constructors.cs b/exercises/concept/constructors/Constructors.cs new file mode 100644 index 0000000000..5aa1a55ebb --- /dev/null +++ b/exercises/concept/constructors/Constructors.cs @@ -0,0 +1,36 @@ +using System; + +class RemoteControlCar +{ + // TODO: define the constructor for the 'RemoteControlCar' class + + public bool BatteryDrained() + { + throw new NotImplementedException("Please implement the RemoteControlCar.BatteryDrained() method"); + } + + public int DistanceDriven() + { + throw new NotImplementedException("Please implement the RemoteControlCar.DistanceDriven() method"); + } + + public void Drive() + { + throw new NotImplementedException("Please implement the RemoteControlCar.Drive() method"); + } + + public static RemoteControlCar TopModel() + { + throw new NotImplementedException("Please implement the (static) RemoteControlCar.TopModel() method"); + } +} + +class RaceTrack +{ + // TODO: define the constructor for the 'RaceTrack' class + + public bool CarCanFinish(RemoteControlCar car) + { + throw new NotImplementedException("Please implement the RaceTrack.CarCanFinish() method"); + } +} diff --git a/exercises/concept/constructors/Constructors.csproj b/exercises/concept/constructors/Constructors.csproj new file mode 100644 index 0000000000..8d66e73a50 --- /dev/null +++ b/exercises/concept/constructors/Constructors.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/constructors/ConstructorsTests.cs b/exercises/concept/constructors/ConstructorsTests.cs new file mode 100644 index 0000000000..f4de32b035 --- /dev/null +++ b/exercises/concept/constructors/ConstructorsTests.cs @@ -0,0 +1,181 @@ +using Xunit; + +public class RemoteControlCarTests +{ + [Fact] + public void NewRemoteControlCarHasNotDrivenAnyDistance() + { + int speed = 10; + int batteryDrain = 2; + var car = new RemoteControlCar(speed, batteryDrain); + + Assert.Equal(0, car.DistanceDriven()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DriveIncreasesDistanceDrivenWithSpeed() + { + int speed = 5; + int batteryDrain = 1; + var car = new RemoteControlCar(speed, batteryDrain); + + car.Drive(); + + Assert.Equal(5, car.DistanceDriven()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DriveDoesNotIncreaseDistanceDrivenWhenBatteryDrained() + { + int speed = 9; + int batteryDrain = 50; + var car = new RemoteControlCar(speed, batteryDrain); + + // Drain the battery + car.Drive(); + car.Drive(); + + // One extra drive attempt (should not succeed) + car.Drive(); + + Assert.Equal(18, car.DistanceDriven()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NewRemoteControlCarBatteryIsNotDrained() + { + int speed = 15; + int batteryDrain = 3; + var car = new RemoteControlCar(speed, batteryDrain); + + Assert.False(car.BatteryDrained()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DriveToAlmostDrainBattery() + { + int speed = 2; + int batteryDrain = 1; + var car = new RemoteControlCar(speed, batteryDrain); + + // Almost drain the battery + for (var i = 0; i < 99; i++) + { + car.Drive(); + } + + Assert.False(car.BatteryDrained()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DriveUntilBatteryIsDrained() + { + int speed = 2; + int batteryDrain = 1; + var car = new RemoteControlCar(speed, batteryDrain); + + // Drain the battery + for (var i = 0; i < 100; i++) + { + car.Drive(); + } + + Assert.True(car.BatteryDrained()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TopOfTheLineCarHasNotDrivenAnyDistance() + { + var car = RemoteControlCar.TopOfTheLine(); + Assert.Equal(0, car.DistanceDriven()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TopOfTheLineCarHasBatteryNotDrained() + { + var car = RemoteControlCar.TopOfTheLine(); + Assert.False(car.BatteryDrained()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TopOfTheLineCarHasCorrectSpeed() + { + var car = RemoteControlCar.TopOfTheLine(); + car.Drive(); + Assert.Equal(50, car.DistanceDriven()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TopOfTheLineHasCorrectBatteryDrain() + { + var car = RemoteControlCar.TopOfTheLine(); + + // The battery is almost drained + for (var i = 0; i < 24; i++) + { + car.Drive(); + } + + Assert.False(car.BatteryDrained()); + + // Drain the battery + car.Drive(); + + Assert.True(car.BatteryDrained()); + } +} + +public class RaceTrackTests +{ + [Fact(Skip = "Remove this Skip property to run this test")] + public void CarCanFinishWithCarThatCanEasilyFinish() + { + int speed = 10; + int batteryDrain = 2; + var car = new RemoteControlCar(speed, batteryDrain); + + int distance = 100; + var race = new RaceTrack(distance); + + Assert.True(race.CarCanFinish(car)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CarCanFinishWithCarThatCanJustFinish() + { + int speed = 2; + int batteryDrain = 10; + var car = new RemoteControlCar(speed, batteryDrain); + + int distance = 20; + var race = new RaceTrack(distance); + + Assert.True(race.CarCanFinish(car)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CarCanFinishWithCarThatJustCannotFinish() + { + int speed = 3; + int batteryDrain = 20; + var car = new RemoteControlCar(speed, batteryDrain); + + int distance = 16; + var race = new RaceTrack(distance); + + Assert.False(race.CarCanFinish(car)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CarCanFinishWithCarThatCannotFinish() + { + int speed = 1; + int batteryDrain = 20; + var car = new RemoteControlCar(speed, batteryDrain); + + int distance = 678; + var race = new RaceTrack(distance); + + Assert.False(race.CarCanFinish(car)); + } +} From 7ceef5bb9f0829b615eef54472f122a140f14336 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 8 May 2020 08:44:10 +0200 Subject: [PATCH 123/327] Add booleans exercise --- exercises/concept/booleans/.docs/after.md | 18 ++ exercises/concept/booleans/.docs/hints.md | 10 + .../concept/booleans/.docs/instructions.md | 60 ++++ .../concept/booleans/.docs/introduction.md | 3 + exercises/concept/booleans/.meta/Example.cs | 22 ++ exercises/concept/booleans/.meta/config.json | 9 + exercises/concept/booleans/.meta/design.md | 38 +++ exercises/concept/booleans/Booleans.cs | 24 ++ exercises/concept/booleans/Booleans.csproj | 13 + exercises/concept/booleans/BooleansTests.cs | 284 ++++++++++++++++++ 10 files changed, 481 insertions(+) create mode 100644 exercises/concept/booleans/.docs/after.md create mode 100644 exercises/concept/booleans/.docs/hints.md create mode 100644 exercises/concept/booleans/.docs/instructions.md create mode 100644 exercises/concept/booleans/.docs/introduction.md create mode 100644 exercises/concept/booleans/.meta/Example.cs create mode 100644 exercises/concept/booleans/.meta/config.json create mode 100644 exercises/concept/booleans/.meta/design.md create mode 100644 exercises/concept/booleans/Booleans.cs create mode 100644 exercises/concept/booleans/Booleans.csproj create mode 100644 exercises/concept/booleans/BooleansTests.cs diff --git a/exercises/concept/booleans/.docs/after.md b/exercises/concept/booleans/.docs/after.md new file mode 100644 index 0000000000..368f4d97db --- /dev/null +++ b/exercises/concept/booleans/.docs/after.md @@ -0,0 +1,18 @@ +Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`. + +C# supports three [boolean operators][operators]: `!` (NOT), `&&` (AND), and `||` (OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. + +```csharp +true || false // => true +true && false // => false +``` + +The three boolean operators each have a different [_operator precedence_][precedence]. As a consequence, they are evaluated in this order: `not` first, `&&` second, and finally `||`. If you want to 'escape' these rules, you can enclose a boolean expression in parentheses (`()`), as the parentheses have an even higher operator precedence. + +```csharp +!true && false // => false +!(true && false) // => true +``` + +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators +[precedence]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#operator-precedence diff --git a/exercises/concept/booleans/.docs/hints.md b/exercises/concept/booleans/.docs/hints.md new file mode 100644 index 0000000000..178a5af90d --- /dev/null +++ b/exercises/concept/booleans/.docs/hints.md @@ -0,0 +1,10 @@ +### General + +- There are three [boolean operators][operators] to work with boolean values. +- Multiple operators can be combined in a single expression. + +### 1. Check if a fast attack can be made + +- The [boolean operators][operators] can also be applied to boolean parameters. + +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators diff --git a/exercises/concept/booleans/.docs/instructions.md b/exercises/concept/booleans/.docs/instructions.md new file mode 100644 index 0000000000..f22f4570f8 --- /dev/null +++ b/exercises/concept/booleans/.docs/instructions.md @@ -0,0 +1,60 @@ +In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing. The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest. Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest. + +After some time spent following her best friend's trail, she finds the camp in which her best friend is imprisoned. It turns out there are two kidnappers: a mighty knight and a cunning archer. + +Having found the kidnappers, Annalyn considers which of the following actions she can engage in: + +- Fast attack: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable. +- Spy: the group can be spied upon if at least one of them is awake. Otherwise, spying is a waste of time. +- Signal prisoner: the prisoner can be signalled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message. +- Free prisoner: if the prisoner is awake and the other two characters are sleeping, a sneaky entry into the camp can free the prisoner. This won't work if the prisoner is sleeping, as the prisoner will be startled by the sudden appearance of her friend and the knight and archer will be awoken. The prisoner can also be freed if the archer is sleeping and Annalyn has her pet dog with her, as the knight will be scared by the dog and will withdraw, and the archer can't equip his bow fast enough to prevent the prisoner from being freed. + +You have four tasks: to implement the logic for determining if the above actions are available based on the state of the three characters found in the forest and whether Annalyn's pet dog is present or not. + +## Tasks + +### 1. Check if a fast attack can be made + +Implement the (_static_) `QuestLogic.CanFastAttack()` method that takes a boolean value that indicates if the knight is awake. This method returns `true` if a fast attack can be made based on the state of the knight. Otherwise, returns `false`: + +```csharp +var knightIsAwake = true; +QuestLogic.CanFastAttack(knightIsAwake); +// => false +``` + +### 2. Check if the group can be spied upon + +Implement the (_static_) `QuestLogic.CanSpy()` method that takes three boolean values, indicating if the knight, archer and the prisoner, respectively, are awake. The method returns `true` if the group can be spied upon, based on the state of the three characters. Otherwise, returns `false`: + +```csharp +var knightIsAwake = false; +var archerIsAwake = true; +var prisonerIsAwake = false; +QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake); +// => true +``` + +### 3. Check if the prisoner can be signalled + +Implement the (_static_) `QuestLogic.CanSignalPrisoner()` method that takes two boolean values, indicating if the archer and the prisoner, respectively, are awake. The method returns `true` if the prisoner can be signalled, based on the state of the two characters. Otherwise, returns `false`: + +```csharp +var archerIsAwake = false; +var prisonerIsAwake = true; +QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake); +// => true +``` + +### 4. Check if the prisoner can be freed + +Implement the (_static_) `QuestLogic.CanFreePrisoner()` method that takes four boolean values. The first three parameters indicate if the knight, archer and the prisoner, respectively, are awake. The last parameter indicates if Annalyn's pet dog is present. The method returns `true` if the prisoner can be freed based on the state of the three characters and Annalyn's pet dog presence. Otherwise, it returns `false`: + +```csharp +var knightIsAwake = false; +var archerIsAwake = true; +var prisonerIsAwake = false; +var petDogIsPresent = false; +QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent); +// => false +``` diff --git a/exercises/concept/booleans/.docs/introduction.md b/exercises/concept/booleans/.docs/introduction.md new file mode 100644 index 0000000000..5341d27350 --- /dev/null +++ b/exercises/concept/booleans/.docs/introduction.md @@ -0,0 +1,3 @@ +Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`. + +C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR). diff --git a/exercises/concept/booleans/.meta/Example.cs b/exercises/concept/booleans/.meta/Example.cs new file mode 100644 index 0000000000..965f407247 --- /dev/null +++ b/exercises/concept/booleans/.meta/Example.cs @@ -0,0 +1,22 @@ +static class QuestLogic +{ + public static bool CanFastAttack(bool knightIsAwake) + { + return !knightIsAwake; + } + + public static bool CanSpy(bool knightIsAwake, bool archerIsAwake, bool prisonerIsAwake) + { + return knightIsAwake || archerIsAwake || prisonerIsAwake; + } + + public static bool CanSignalPrisoner(bool archerIsAwake, bool prisonerIsAwake) + { + return !archerIsAwake && prisonerIsAwake; + } + + public static bool CanFreePrisoner(bool knightIsAwake, bool archerIsAwake, bool prisonerIsAwake, bool petDogIsPresent) + { + return !knightIsAwake && !archerIsAwake && prisonerIsAwake || !archerIsAwake && petDogIsPresent; + } +} diff --git a/exercises/concept/booleans/.meta/config.json b/exercises/concept/booleans/.meta/config.json new file mode 100644 index 0000000000..6ae20d183e --- /dev/null +++ b/exercises/concept/booleans/.meta/config.json @@ -0,0 +1,9 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "forked_from": ["fsharp/booleans"] +} diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/booleans/.meta/design.md new file mode 100644 index 0000000000..5a60eefc7a --- /dev/null +++ b/exercises/concept/booleans/.meta/design.md @@ -0,0 +1,38 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Booleans in C#. + +## Learning objectives + +- Know of the existence of the `bool` type and its two values. +- Know about boolean operators and how to build logical expressions with them. +- Know of the boolean operator precedence rules. + +## Out of scope + +- Pattern matching on booleans. + +## Concepts + +The Concepts this exercise unlocks are: + +- `booleans`: know of the existence of the `bool` type and its two values; know about boolean operators and how to build logical expressions with them; know of the boolean operator precedence rules. + +## Prequisites + +This exercise's prerequisites Concepts are: + +- `basics`: know how to define methods. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific logic to be added to the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/booleans/Booleans.cs b/exercises/concept/booleans/Booleans.cs new file mode 100644 index 0000000000..86e2bcd964 --- /dev/null +++ b/exercises/concept/booleans/Booleans.cs @@ -0,0 +1,24 @@ +using System; + +static class QuestLogic +{ + public static bool CanFastAttack(bool knightIsAwake) + { + throw new NotImplementedException("Please implement the (static) QuestLogic.CanFastAttack() method"); + } + + public static bool CanSpy(bool knightIsAwake, bool archerIsAwake, bool prisonerIsAwake) + { + throw new NotImplementedException("Please implement the (static) QuestLogic.CanSpy() method"); + } + + public static bool CanSignalPrisoner(bool archerIsAwake, bool prisonerIsAwake) + { + throw new NotImplementedException("Please implement the (static) QuestLogic.CanSignalPrisoner() method"); + } + + public static bool CanFreePrisoner(bool knightIsAwake, bool archerIsAwake, bool prisonerIsAwake, bool petDogIsPresent) + { + throw new NotImplementedException("Please implement the (static) QuestLogic.CanFreePrisoner() method"); + } +} diff --git a/exercises/concept/booleans/Booleans.csproj b/exercises/concept/booleans/Booleans.csproj new file mode 100644 index 0000000000..8d66e73a50 --- /dev/null +++ b/exercises/concept/booleans/Booleans.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/booleans/BooleansTests.cs b/exercises/concept/booleans/BooleansTests.cs new file mode 100644 index 0000000000..f293e92f7e --- /dev/null +++ b/exercises/concept/booleans/BooleansTests.cs @@ -0,0 +1,284 @@ +using Xunit; + +public class QuestLogicTests +{ + [Fact] + public void CannotExecuteFastAttackIfKnightIsAwake() + { + var knightIsAwake = true; + Assert.False(QuestLogic.CanFastAttack(knightIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanExecuteFastAttackIfKnightIsSleeping() + { + var knightIsAwake = false; + Assert.True(QuestLogic.CanFastAttack(knightIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotSpyIfEveryoneIsSleeping() + { + var knightIsAwake = false; + var archerIsAwake = false; + var prisonerIsAwake = false; + Assert.False(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfEveryoneButKnightIsSleeping() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = false; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfEveryoneButArcherIsSleeping() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = false; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfEveryoneButPrisonerIsSleeping() + { + var knightIsAwake = false; + var archerIsAwake = false; + + + var prisonerIsAwake = true; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfOnlyKnightIsSleeping() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = true; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfOnlyArcherIsSleeping() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = true; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfOnlyPrisonerIsSleeping() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = false; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSpyIfEveryoneIsAwake() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = true; + Assert.True(QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanSignalPrisonerIfarcherIsSleepingAndPrisonerIsAwake() + { + var archerIsAwake = false; + var prisonerIsAwake = true; + Assert.True(QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotSignalPrisonerIfarcherIsAwakeAndPrisonerIsSleeping() + { + var archerIsAwake = true; + var prisonerIsAwake = false; + Assert.False(QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotSignalPrisonerIfarcherAndPrisonerAreBothSleeping() + { + var archerIsAwake = false; + var prisonerIsAwake = false; + Assert.False(QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotSignalPrisonerIfarcherAndPrisonerAreBothAwake() + { + var archerIsAwake = true; + var prisonerIsAwake = true; + Assert.False(QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsPresent() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = true; + var petDogIsPresent = true; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsAbsent() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = true; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanReleasePrisonerIfEveryoneIsAsleepAndPetDogIsPresent() + { + var knightIsAwake = false; + var archerIsAwake = false; + var prisonerIsAwake = false; + var petDogIsPresent = true; + Assert.True(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfEveryoneIsAsleepAndPetDogIsAbsent() + { + var knightIsAwake = false; + var archerIsAwake = false; + var prisonerIsAwake = false; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsPresent() + { + var knightIsAwake = false; + var archerIsAwake = false; + var prisonerIsAwake = true; + var petDogIsPresent = true; + Assert.True(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsAbsent() + { + var knightIsAwake = false; + var archerIsAwake = false; + var prisonerIsAwake = true; + var petDogIsPresent = false; + Assert.True(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsPresent() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = false; + var petDogIsPresent = true; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsAbsent() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = false; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsPresent() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = false; + var petDogIsPresent = true; + Assert.True(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsAbsent() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = false; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsPresent() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = true; + var petDogIsPresent = true; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsAbsent() + { + var knightIsAwake = false; + var archerIsAwake = true; + var prisonerIsAwake = true; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CanReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsPresent() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = true; + var petDogIsPresent = true; + Assert.True(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsAbsent() + { + var knightIsAwake = true; + var archerIsAwake = false; + var prisonerIsAwake = true; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsPresent() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = false; + var petDogIsPresent = true; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsAbsent() + { + var knightIsAwake = true; + var archerIsAwake = true; + var prisonerIsAwake = false; + var petDogIsPresent = false; + Assert.False(QuestLogic.CanFreePrisoner(knightIsAwake, archerIsAwake, prisonerIsAwake, petDogIsPresent)); + } +} From 055ff8d36b91800ea96c9214b0ed03b7a42b5f62 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 8 May 2020 08:44:23 +0200 Subject: [PATCH 124/327] Minor instructions consistency fix --- exercises/concept/constructors/.docs/instructions.md | 1 + exercises/concept/properties/.docs/instructions.md | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/exercises/concept/constructors/.docs/instructions.md b/exercises/concept/constructors/.docs/instructions.md index f591384849..25de2d29fe 100644 --- a/exercises/concept/constructors/.docs/instructions.md +++ b/exercises/concept/constructors/.docs/instructions.md @@ -64,6 +64,7 @@ var car = RemoteControlCar.Nitro(); car.Drive(); car.DistanceDriven(); // => 50 + ### 6. Check if a remote control car can finish a race To finish a race, a car has to be able to drive the race's distance. This means not draining its battery before having crossed the finish line. Implement the `Race.CarCanFinish()` method that takes a `RemoteControlCar` instance as its parameter and returns `true` if the car can finish the race; otherwise, return `false`: diff --git a/exercises/concept/properties/.docs/instructions.md b/exercises/concept/properties/.docs/instructions.md index 7bc8a680df..c0ef53d0b4 100644 --- a/exercises/concept/properties/.docs/instructions.md +++ b/exercises/concept/properties/.docs/instructions.md @@ -29,7 +29,7 @@ For Example: You have 5 tasks each of which requires you to implement one or more properties: -### 1 Allow the weight to be set on the weighing machine +### 1. Allow the weight to be set on the weighing machine Implement the `WeigingMachine.InputWeight` property to allow the weight to be get and set: @@ -40,7 +40,7 @@ wm.InputWeight = 60m; // => wm.InputWeight == 60m ``` -### 2 Ensure that a negative input weight is rejected. +### 2. Ensure that a negative input weight is rejected Add validation to the `WeighingMachine.InputWeight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight: @@ -49,7 +49,7 @@ var wm = new WeighingMachine(); wm.InputWeight = -10m; // Throws an ArgumentException ``` -### 3 Allow the US weight to be retrieved +### 3. Allow the US weight to be retrieved Implement the `WeighingMachine.USDisplayWeight` property and the `USWeight` class: @@ -61,7 +61,7 @@ var usw = wm.USDisplayWeight; // => usw.Pounds == 132 && usw.Ounces == 4 ``` -### 4 Allow the machine's units to be set to pounds +### 4. Allow the machine's units to be set to pounds Implement the `WeighingMachine.Units` property: @@ -74,7 +74,7 @@ var usw = wm.USDisplayWeight; // => usw.Pounds == 175 && usw.Ounces == 8 ``` -### 5 Allow a tare adjustment to be applied to the weighing machine +### 5. Allow a tare adjustment to be applied to the weighing machine Implement the `WeighingMachine.TareAdjustment` and `WeighingMachine.DisplayWeight` properties: From 14bfc3aa0adcd09188b034c0340b0edab842ab90 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 8 May 2020 15:14:31 +0200 Subject: [PATCH 125/327] Cleanup --- exercises/concept/nullability/.meta/design.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index bca3a22d32..87e98ecfeb 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -33,8 +33,7 @@ This Concept Exercise's prerequisites Concepts are: - `strings`: strings will be compared to `null` and basic methods from strings will be called. - `basics`: integers will be compared to `null`, arithmetic operations will be performed on integers, variables will be introduced and updated. -- `exceptions`: explain how a `NullReferenceException` is thrown when accessing a `null` value. -- `for-loops`: strings will be processed and constructed iteratively. +- `conditionals`: using a conditional statement. - `memory-allocation`: reference and value types will be used in their nullable and non-nullable variants. ## Representer From 384efbb725f3d725a025439895dad4109b6934f3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 15 May 2020 15:22:10 +0200 Subject: [PATCH 126/327] Add inheritance exercise Add inheritance exercise Co-authored-by: Jeremy Walker --- exercises/concept/inheritance/.docs/after.md | 73 +++++++++++++++++ exercises/concept/inheritance/.docs/hints.md | 33 ++++++++ .../concept/inheritance/.docs/instructions.md | 81 +++++++++++++++++++ .../concept/inheritance/.docs/introduction.md | 61 ++++++++++++++ .../concept/inheritance/.meta/Example.cs | 67 +++++++++++++++ .../concept/inheritance/.meta/config.json | 8 ++ exercises/concept/inheritance/.meta/design.md | 49 +++++++++++ exercises/concept/inheritance/Inheritance.cs | 50 ++++++++++++ .../concept/inheritance/Inheritance.csproj | 13 +++ .../concept/inheritance/InheritanceTests.cs | 67 +++++++++++++++ 10 files changed, 502 insertions(+) create mode 100644 exercises/concept/inheritance/.docs/after.md create mode 100644 exercises/concept/inheritance/.docs/hints.md create mode 100644 exercises/concept/inheritance/.docs/instructions.md create mode 100644 exercises/concept/inheritance/.docs/introduction.md create mode 100644 exercises/concept/inheritance/.meta/Example.cs create mode 100644 exercises/concept/inheritance/.meta/config.json create mode 100644 exercises/concept/inheritance/.meta/design.md create mode 100644 exercises/concept/inheritance/Inheritance.cs create mode 100644 exercises/concept/inheritance/Inheritance.csproj create mode 100644 exercises/concept/inheritance/InheritanceTests.cs diff --git a/exercises/concept/inheritance/.docs/after.md b/exercises/concept/inheritance/.docs/after.md new file mode 100644 index 0000000000..90a7a0fd83 --- /dev/null +++ b/exercises/concept/inheritance/.docs/after.md @@ -0,0 +1,73 @@ +In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. To prevent a class being inherited, add the [`sealed` modifier][sealed-classes]. + +Parent classes can provide functionality to derived classes in three ways: + +- Define a regular method. +- Define a [`virtual` method][virtual-keyword], which is like a regular method but one that derived classes _can_ change. +- Define an [`abstract` method][abstract-keyword], which is a method without an implementation that derived classes _must_ implement. A class with `abstract` methods must be marked as [`abstract`][abstract-classes] too. Abstract classes cannot be instantiated. + +The [`protected` access modifier][protected-keyword] allows a parent class member to be accessed in a derived class, but blocks access from other classes. Derived classes thus can access `public` and `protected` parent class members, but not `private` parent class members. + +Derived classes can access parent class members through the [`base` keyword][base-keyword]. + +```csharp +// Inherits from the 'object' class +abstract class Vehicle +{ + // Can be overridden + public virtual void Drive() + { + } + + // Must be overridden + protected abstract int Speed(); +} + +// Cannot be inherited from +sealed class Car : Vehicle +{ + public override void Drive() + { + // Override virtual method + + // Call parent implementation + base.Drive(); + } + + protected override int Speed() + { + // Implement abstract method + } +} +``` + +The constructor of a derived class will [automatically call its parent's constructor][constructors] _before_ executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the [`base` keyword][base-keyword-constructor]. As abstract classes cannot be instantiated, their constructors can be made `protected`. + +```csharp +abstract class Vehicle +{ + protected Vehicle(int wheels) + { + Console.WriteLine("Called first"); + } +} + +class Car : Vehicle +{ + public Car() : base(4) + { + Console.WriteLine("Called second"); + } +} +``` + +[abstract-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract +[virtual-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual +[override-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override +[base-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base +[base-keyword-constructor]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base#example-1 +[protected-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected +[sealed-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed +[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors +[abstract-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#abstract-classes-and-class-members +[sealed-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members diff --git a/exercises/concept/inheritance/.docs/hints.md b/exercises/concept/inheritance/.docs/hints.md new file mode 100644 index 0000000000..70dcec008f --- /dev/null +++ b/exercises/concept/inheritance/.docs/hints.md @@ -0,0 +1,33 @@ +### 1. Describe a character + +- Modify the [constructors][constructor-syntax] of the `Wizard` and `Warrior` classes to pass their character type to the [base class' constructor][instance-constructors]. +- Store the character type as a [field][fields] on the `Character` class. +- The `Character` class implicitly inherits from the `object` class, which [`ToString()` method you can override][override-tostring]. + +### 2. Make characters not vulnerable by default + +- Implement the `Vulnerable()` method in the `Character` class to always return `false`. + +### 3. Allow Wizards to prepare a spell + +- Add a field to the `Wizard` class to store if a spell was prepared and update this in the `PrepareSpell()` method. +- The spell should start out as not being prepared. + +### 4. Make Wizards vulnerable when not having prepared a spell + +- Override the `Vulnerable()` method in the `Wizard` class to make Wizards vulnerable if they haven't prepared a spell. + +### 5. Calculate the damage points for a Wizard + +- Use a [conditional statement][if-else] to return the the damage points, taking into account the value of the prepare spell field. + +### 6. Calculate the damage points for a Warrior + +- You can call a method on the passed `Character` instance to determine its vulnerability. +- Use a [conditional statement][if-else] to return the the damage points, taking into account the vulnerability of the target. + +[constructor-syntax]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax +[instance-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[override-tostring]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-override-the-tostring-method +[if-else]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else diff --git a/exercises/concept/inheritance/.docs/instructions.md b/exercises/concept/inheritance/.docs/instructions.md new file mode 100644 index 0000000000..11a1f234a8 --- /dev/null +++ b/exercises/concept/inheritance/.docs/instructions.md @@ -0,0 +1,81 @@ +In this exercise you're playing a role-playing game named "Wizard and Warriors," which allows you to play as either a Wizard or a Warrior. + +There are different rules for Warriors and Wizards to determine how much damage points they deal. + +For a Warrior, these are the rules: + +- Deal 6 points of damage if the character they are attacking is not vulnerable +- Deal 10 points of damage if the character they are attacking is vulnerable + +For a Wizard, these are the rules: + +- Deal 12 points of damage if the Wizard prepared a spell in advanced +- Deal 3 points of damage if the Wizard did not prepare a spell in advance + +In general, characters are never vulnerable. However, Wizards _are_ vulnerable if they haven't prepared a spell. + +You have six tasks that work with Warriors and Wizard characters. + +### 1. Describe a character + +Override the `ToString()` method on the `Character` class to return a description of the character, formatted as `"Character is a "`. + +```csharp +var warrior = new Warrior(); +warrior.ToString(); +// => "Character is a Warrior" +``` + +### 2. Make characters not vulnerable by default + +Ensure that the `Character.Vulnerable()` method always returns `false`. + +```csharp +var warrior = new Warrior(); +warrior.Vulnerable(); +// => false +``` + +### 3. Allow Wizards to prepare a spell + +Implement the `Wizard.PrepareSpell()` method to allow a Wizard to prepare a spell in advance. + +```csharp +var wizard = new Wizard(); +wizard.PrepareSpell(); +``` + +### 4. Make Wizards vulnerable when not having prepared a spell + +Ensure that the `Vulnerable()` method returns `true` if the wizard did not prepare a spell; otherwise, return `false`. + +```csharp +var wizard = new Wizard(); +wizard.Vulnerable(); +// => true +``` + +### 5. Calculate the damage points for a Wizard + +Implement the `Wizard.DamagePoints()` method to return the damage points dealt: 12 damage points when a spell has been prepared, 3 damage points when not. + +```csharp +var wizard = new Wizard(); +var warrior = new Warrior(); + +wizard.PrepareSpell(); +wizard.DamagePoints(warrior); +// => 12 +``` + +### 6. Calculate the damage points for a Warrior + +Implement the `Warrior.DamagePoints()` method to return the damage points dealt: 10 damage points when the target is vulnerable, 6 damage points when not. + +```csharp +var warrior = new Warrior(); +var wizard = new Wizard(); + +warrior.DamagePoints(wizard); +// => 10 +``` diff --git a/exercises/concept/inheritance/.docs/introduction.md b/exercises/concept/inheritance/.docs/introduction.md new file mode 100644 index 0000000000..d2d7333a82 --- /dev/null +++ b/exercises/concept/inheritance/.docs/introduction.md @@ -0,0 +1,61 @@ +In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. + +Parent classes can provide functionality to derived classes in three ways: + +- Define a regular method. +- Define a `virtual` method, which is like a regular method but one that derived classes _can_ change. +- Define an `abstract` method, which is a method without an implementation that derived classes _must_ implement. A class with `abstract` methods must be marked as `abstract` too. Abstract classes cannot be instantiated. + +The `protected` access modifier allows a parent class member to be accessed in a derived class, but blocks access from other classes. + +Derived classes can access parent class members through the `base` keyword. + +```csharp +// Inherits from the 'object' class +abstract class Vehicle +{ + // Can be overridden + public virtual void Drive() + { + } + + // Must be overridden + protected abstract int Speed(); +} + +class Car : Vehicle +{ + public override void Drive() + { + // Override virtual method + + // Call parent implementation + base.Drive(); + } + + protected override int Speed() + { + // Implement abstract method + } +} +``` + +The constructor of a derived class will automatically call its parent's constructor _before_ executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the `base` keyword: + +```csharp +abstract class Vehicle +{ + protected Vehicle(int wheels) + { + Console.WriteLine("Called first"); + } +} + +class Car : Vehicle +{ + public Car() : base(4) + { + Console.WriteLine("Called second"); + } +} +``` diff --git a/exercises/concept/inheritance/.meta/Example.cs b/exercises/concept/inheritance/.meta/Example.cs new file mode 100644 index 0000000000..18bba0ffd4 --- /dev/null +++ b/exercises/concept/inheritance/.meta/Example.cs @@ -0,0 +1,67 @@ +abstract class Character +{ + private string characterType; + + protected Character(string characterType) + { + this.characterType = characterType; + } + + public abstract int DamagePoints(Character target); + + public virtual bool Vulnerable() + { + return false; + } + + public override string ToString() + { + return $"Character is a {characterType}"; + } +} + +class Warrior : Character +{ + public Warrior() : base("Warrior") + { + } + + public override int DamagePoints(Character target) + { + if (target.Vulnerable()) + { + return 10; + } + + return 6; + } +} + +class Wizard : Character +{ + private bool spellPrepared; + + public Wizard() : base("Wizard") + { + } + + public override int DamagePoints(Character target) + { + if (spellPrepared) + { + return 12; + } + + return 3; + } + + public void PrepareSpell() + { + spellPrepared = true; + } + + public override bool Vulnerable() + { + return !spellPrepared; + } +} diff --git a/exercises/concept/inheritance/.meta/config.json b/exercises/concept/inheritance/.meta/config.json new file mode 100644 index 0000000000..6d4e44d872 --- /dev/null +++ b/exercises/concept/inheritance/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md new file mode 100644 index 0000000000..3b2f40294c --- /dev/null +++ b/exercises/concept/inheritance/.meta/design.md @@ -0,0 +1,49 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the Concept of Inheritance in C#. + +## Learning objectives + +- Know what inheritance is. +- Know how to inherit from a class. +- Know that all types inherit from `object`. +- Know what abstract and sealed classes are. +- Know what abstract and virtual methods are. +- Know how to override methods. +- Know about the `protected` visibility modifier. + +## Out of scope + +- Extending types through extension methods. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `inheritance`: know what inheritance is; know how to inherit from a class; know that all types inherit from `object`; know what abstract and sealed classes are; know what abstract and virtual methods are; know how to override methods; know about the `protected` visibility modifier. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `classes`: know how to work with classes. +- `constructors`: know how to work with constructors. +- `strings`: know how to do basic string interpolation. +- `boolean`: know how to use boolean logic. +- `conditionals`: know how to do conditional logic. + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise could benefit from the following rules added to the the [analyzer][analyzer]: + +- Verify that the constructor of the `Character` class uses the `protected` modifier. +- Verify that the various fields used (hit points, spell prepared and potion drunk) use the `private` modifier. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/inheritance/Inheritance.cs b/exercises/concept/inheritance/Inheritance.cs new file mode 100644 index 0000000000..c3c785db07 --- /dev/null +++ b/exercises/concept/inheritance/Inheritance.cs @@ -0,0 +1,50 @@ +using System; + +abstract class Character +{ + protected Character(string characterType) + { + throw new NotImplementedException("Please implement the Character() constructor"); + } + + public abstract int DamagePoints(Character target); + + public virtual bool Vulnerable() + { + throw new NotImplementedException("Please implement the Character.Vulnerable() method"); + } + + public override string ToString() + { + throw new NotImplementedException("Please implement the Character.ToString() method"); + } +} + +class Warrior : Character +{ + public Warrior() : base("TODO") + { + } + + public override int DamagePoints(Character target) + { + throw new NotImplementedException("Please implement the Warrior.DamagePoints() method"); + } +} + +class Wizard : Character +{ + public Wizard() : base("TODO") + { + } + + public override int DamagePoints(Character target) + { + throw new NotImplementedException("Please implement the Wizard.DamagePoints() method"); + } + + public void PrepareSpell() + { + throw new NotImplementedException("Please implement the Wizard.PrepareSpell() method"); + } +} diff --git a/exercises/concept/inheritance/Inheritance.csproj b/exercises/concept/inheritance/Inheritance.csproj new file mode 100644 index 0000000000..8d66e73a50 --- /dev/null +++ b/exercises/concept/inheritance/Inheritance.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/inheritance/InheritanceTests.cs b/exercises/concept/inheritance/InheritanceTests.cs new file mode 100644 index 0000000000..f71519a7c1 --- /dev/null +++ b/exercises/concept/inheritance/InheritanceTests.cs @@ -0,0 +1,67 @@ +using Xunit; + +public class RolePlayingGameTests +{ + [Fact] + public void Describe_wizard() + { + var wizard = new Wizard(); + Assert.Equal("Character is a Wizard", wizard.ToString()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_warrior() + { + var warrior = new Warrior(); + Assert.Equal("Character is a Warrior", warrior.ToString()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Warrior_is_not_vulnerable() + { + var warrior = new Warrior(); + Assert.False(warrior.Vulnerable()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Wizard_is_not_vulnerable() + { + var wizard = new Wizard(); + Assert.False(wizard.Vulnerable()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Wizard_with_prepared_spell_is_not_vulnerable() + { + var wizard = new Wizard(); + wizard.PrepareSpell(); + Assert.False(wizard.Vulnerable()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Wizard_with_no_prepared_spell_is_vulnerable() + { + var wizard = new Wizard(); + Assert.True(wizard.Vulnerable()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Attack_points_for_wizard_with_prepared_spell() + { + var wizard = new Wizard(); + var warrior = new Warrior(); + + wizard.PrepareSpell(); + + Assert.Equal(12, wizard.DamagePoints(warrior)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Attack_points_for_wizard_with_no_prepared_spell() + { + var wizard = new Wizard(); + var otherWizard = new Wizard(); + + Assert.Equal(3, wizard.DamagePoints(otherWizard)); + } +} From 8c24cfb295317df33cfc8cc15f2999458108148d Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 15 May 2020 15:05:06 +0100 Subject: [PATCH 127/327] Minor corrections to document --- exercises/concept/datetimes/.docs/after.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/concept/datetimes/.docs/after.md b/exercises/concept/datetimes/.docs/after.md index aee6bac0de..d92f0b6f52 100644 --- a/exercises/concept/datetimes/.docs/after.md +++ b/exercises/concept/datetimes/.docs/after.md @@ -4,9 +4,10 @@ Manipulating a `DateTime` can be done by calling one of its [methods][methods]. Comparing `DateTime` instances can be done using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the `DateTime.Now` property. -An important aspect of dates in F# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s will be dependent on the current culture. This includes the [`DateTime.Parse()` method][parse] that parses a `string` to a `DateTime`, as well as the `DateTime` class' [`ToString()` method][to-string] that converts a `DateTime` to a `string`. +An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s will be dependent on the current culture. This includes the [`DateTime.Parse()` method][parse] that parses a `string` to a `DateTime`, as well as the `DateTime` class' [`ToString()` method][to-string] that converts a `DateTime` to a `string`. [parse]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netcore-3.1#System_DateTime_Parse_System_String_ [operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#operators [properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#properties [to-string]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=netcore-3.1 +[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#methods From c67b0ee7ff297b2df7cdb985f882eca145d7f8c2 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 16 May 2020 12:19:29 +0200 Subject: [PATCH 128/327] Update test naming * Use consistent test method names * Update docs on test method naming --- exercises/concept/arrays/ArraysTests.cs | 18 +++--- exercises/concept/basics/BasicsTests.cs | 12 ++-- exercises/concept/booleans/BooleansTests.cs | 60 +++++++++---------- exercises/concept/classes/ClassesTests.cs | 20 +++---- .../concept/constructors/ConstructorsTests.cs | 28 ++++----- exercises/concept/datetimes/DateTimesTests.cs | 50 ++++++++-------- exercises/concept/enums/EnumsTests.cs | 28 ++++----- .../concept/flag-enums/FlagEnumsTests.cs | 44 +++++++------- .../FloatingPointNumbersTests.cs | 48 +++++++-------- .../concept/nullability/NullabilityTests.cs | 8 +-- exercises/concept/numbers/NumbersTests.cs | 24 ++++---- .../concept/properties/PropertiesTests.cs | 4 +- exercises/concept/strings/StringsTests.cs | 22 +++---- reference/implementing-a-concept-exercise.md | 2 + 14 files changed, 185 insertions(+), 183 deletions(-) diff --git a/exercises/concept/arrays/ArraysTests.cs b/exercises/concept/arrays/ArraysTests.cs index 9d6add90a7..4ca20a88ea 100644 --- a/exercises/concept/arrays/ArraysTests.cs +++ b/exercises/concept/arrays/ArraysTests.cs @@ -3,13 +3,13 @@ public class BirdCountTests { [Fact(Skip = "Remove this Skip property to run this test")] - public void LastWeek() + public void Last_week() { Assert.Equal(new int[] { 0, 2, 5, 3, 7, 8, 4 }, BirdCount.LastWeek()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void YesterdayForDisappointingWeek() + public void Yesterday_for_disappointing_week() { var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; var birdCount = new BirdCount(counts); @@ -17,7 +17,7 @@ public void YesterdayForDisappointingWeek() } [Fact(Skip = "Remove this Skip property to run this test")] - public void YesterdayDaysForBusyWeek() + public void Yesterday_days_for_busy_week() { var counts = new int[] { 8, 8, 9, 5, 4, 7, 10 }; var birdCount = new BirdCount(counts); @@ -25,7 +25,7 @@ public void YesterdayDaysForBusyWeek() } [Fact] - public void TotalForDisappointingWeek() + public void Total_for_disappointing_week() { var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; var birdCount = new BirdCount(counts); @@ -33,7 +33,7 @@ public void TotalForDisappointingWeek() } [Fact(Skip = "Remove this Skip property to run this test")] - public void TotalForBusyWeek() + public void Total_for_busy_week() { var counts = new int[] { 5, 9, 12, 6, 8, 8, 17 }; var birdCount = new BirdCount(counts); @@ -41,7 +41,7 @@ public void TotalForBusyWeek() } [Fact(Skip = "Remove this Skip property to run this test")] - public void BusyDaysForDisappointingWeek() + public void Busy_days_for_disappointing_week() { var counts = new int[] { 1, 1, 1, 0, 0, 0, 0 }; var birdCount = new BirdCount(counts); @@ -49,7 +49,7 @@ public void BusyDaysForDisappointingWeek() } [Fact(Skip = "Remove this Skip property to run this test")] - public void BusyDaysForBusyWeek() + public void Busy_days_for_busy_week() { var counts = new int[] { 4, 9, 5, 7, 8, 8, 2 }; var birdCount = new BirdCount(counts); @@ -57,7 +57,7 @@ public void BusyDaysForBusyWeek() } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasDayWithoutBirdsWithDayWithoutBirds() + public void Has_day_without_birds_with_day_without_birds() { var counts = new int[] { 5, 5, 4, 0, 7, 6, 7 }; var birdCount = new BirdCount(counts); @@ -65,7 +65,7 @@ public void HasDayWithoutBirdsWithDayWithoutBirds() } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasDayWithoutBirdsWithNoDayWithoutBirds() + public void Has_day_without_birds_with_no_day_without_birds() { var counts = new int[] { 4, 5, 9, 10, 9, 4, 3 }; var birdCount = new BirdCount(counts); diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs index 1feccb141c..0b0753d08f 100644 --- a/exercises/concept/basics/BasicsTests.cs +++ b/exercises/concept/basics/BasicsTests.cs @@ -3,37 +3,37 @@ public class LasagnaTests { [Fact] - public void ExpectedMinutesInOven() + public void Expected_minutes_in_oven() { Assert.Equal(40, new Lasagna().ExpectedMinutesInOven()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RemainingMinutesInOven() + public void Remaining_minutes_in_oven() { Assert.Equal(15, new Lasagna().RemainingMinutesInOven(25)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void PreparationTimeInMinutesForOneLayer() + public void Preparation_time_in_minutes_for_one_layer() { Assert.Equal(2, new Lasagna().PreparationTimeInMinutes(1)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void PreparationTimeInMinutesForMultipleLayers() + public void Preparation_time_in_minutes_for_multiple_layers() { Assert.Equal(8, new Lasagna().PreparationTimeInMinutes(4)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TotalTimeInMinutesForOneLayer() + public void Total_time_in_minutes_for_one_layer() { Assert.Equal(32, new Lasagna().TotalTimeInMinutes(1, 30)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TotalTimeInMinutesForMultipleLayers() + public void Total_time_in_minutes_for_multiple_layers() { Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); } diff --git a/exercises/concept/booleans/BooleansTests.cs b/exercises/concept/booleans/BooleansTests.cs index f293e92f7e..7221271bfd 100644 --- a/exercises/concept/booleans/BooleansTests.cs +++ b/exercises/concept/booleans/BooleansTests.cs @@ -3,21 +3,21 @@ public class QuestLogicTests { [Fact] - public void CannotExecuteFastAttackIfKnightIsAwake() + public void Cannot_execute_fast_attack_if_knight_is_awake() { var knightIsAwake = true; Assert.False(QuestLogic.CanFastAttack(knightIsAwake)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanExecuteFastAttackIfKnightIsSleeping() + public void Can_execute_fast_attack_if_knight_is_sleeping() { var knightIsAwake = false; Assert.True(QuestLogic.CanFastAttack(knightIsAwake)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotSpyIfEveryoneIsSleeping() + public void Cannot_spy_if_everyone_is_sleeping() { var knightIsAwake = false; var archerIsAwake = false; @@ -26,7 +26,7 @@ public void CannotSpyIfEveryoneIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfEveryoneButKnightIsSleeping() + public void Can_spy_if_everyone_but_knight_is_sleeping() { var knightIsAwake = true; var archerIsAwake = false; @@ -35,7 +35,7 @@ public void CanSpyIfEveryoneButKnightIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfEveryoneButArcherIsSleeping() + public void Can_spy_if_everyone_but_archer_is_sleeping() { var knightIsAwake = false; var archerIsAwake = true; @@ -44,7 +44,7 @@ public void CanSpyIfEveryoneButArcherIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfEveryoneButPrisonerIsSleeping() + public void Can_spy_if_everyone_but_prisoner_is_sleeping() { var knightIsAwake = false; var archerIsAwake = false; @@ -55,7 +55,7 @@ public void CanSpyIfEveryoneButPrisonerIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfOnlyKnightIsSleeping() + public void Can_spy_if_only_knight_is_sleeping() { var knightIsAwake = false; var archerIsAwake = true; @@ -64,7 +64,7 @@ public void CanSpyIfOnlyKnightIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfOnlyArcherIsSleeping() + public void Can_spy_if_only_archer_is_sleeping() { var knightIsAwake = true; var archerIsAwake = false; @@ -73,7 +73,7 @@ public void CanSpyIfOnlyArcherIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfOnlyPrisonerIsSleeping() + public void Can_spy_if_only_prisoner_is_sleeping() { var knightIsAwake = true; var archerIsAwake = true; @@ -82,7 +82,7 @@ public void CanSpyIfOnlyPrisonerIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSpyIfEveryoneIsAwake() + public void Can_spy_if_everyone_is_awake() { var knightIsAwake = true; var archerIsAwake = true; @@ -91,7 +91,7 @@ public void CanSpyIfEveryoneIsAwake() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanSignalPrisonerIfarcherIsSleepingAndPrisonerIsAwake() + public void Can_signal_prisoner_ifarcher_is_sleeping_and_prisoner_is_awake() { var archerIsAwake = false; var prisonerIsAwake = true; @@ -99,7 +99,7 @@ public void CanSignalPrisonerIfarcherIsSleepingAndPrisonerIsAwake() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotSignalPrisonerIfarcherIsAwakeAndPrisonerIsSleeping() + public void Cannot_signal_prisoner_ifarcher_is_awake_and_prisoner_is_sleeping() { var archerIsAwake = true; var prisonerIsAwake = false; @@ -107,7 +107,7 @@ public void CannotSignalPrisonerIfarcherIsAwakeAndPrisonerIsSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotSignalPrisonerIfarcherAndPrisonerAreBothSleeping() + public void Cannot_signal_prisoner_ifarcher_and_prisoner_are_both_sleeping() { var archerIsAwake = false; var prisonerIsAwake = false; @@ -115,7 +115,7 @@ public void CannotSignalPrisonerIfarcherAndPrisonerAreBothSleeping() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotSignalPrisonerIfarcherAndPrisonerAreBothAwake() + public void Cannot_signal_prisoner_ifarcher_and_prisoner_are_both_awake() { var archerIsAwake = true; var prisonerIsAwake = true; @@ -123,7 +123,7 @@ public void CannotSignalPrisonerIfarcherAndPrisonerAreBothAwake() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsPresent() + public void Cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_present() { var knightIsAwake = true; var archerIsAwake = true; @@ -133,7 +133,7 @@ public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_everyone_is_awake_and_pet_dog_is_absent() { var knightIsAwake = true; var archerIsAwake = true; @@ -143,7 +143,7 @@ public void CannotReleasePrisonerIfEveryoneIsAwakeAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanReleasePrisonerIfEveryoneIsAsleepAndPetDogIsPresent() + public void Can_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_present() { var knightIsAwake = false; var archerIsAwake = false; @@ -153,7 +153,7 @@ public void CanReleasePrisonerIfEveryoneIsAsleepAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfEveryoneIsAsleepAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_everyone_is_asleep_and_pet_dog_is_absent() { var knightIsAwake = false; var archerIsAwake = false; @@ -163,7 +163,7 @@ public void CannotReleasePrisonerIfEveryoneIsAsleepAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsPresent() + public void Can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_present() { var knightIsAwake = false; var archerIsAwake = false; @@ -173,7 +173,7 @@ public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsAbsent() + public void Can_release_prisoner_if_only_prisoner_is_awake_and_pet_dog_is_absent() { var knightIsAwake = false; var archerIsAwake = false; @@ -183,7 +183,7 @@ public void CanReleasePrisonerIfOnlyPrisonerIsAwakeAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsPresent() + public void Cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_present() { var knightIsAwake = false; var archerIsAwake = true; @@ -193,7 +193,7 @@ public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_only_archer_is_awake_and_pet_dog_is_absent() { var knightIsAwake = false; var archerIsAwake = true; @@ -203,7 +203,7 @@ public void CannotReleasePrisonerIfOnlyArcherIsAwakeAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsPresent() + public void Can_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_present() { var knightIsAwake = true; var archerIsAwake = false; @@ -213,7 +213,7 @@ public void CanReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_only_knight_is_awake_and_pet_dog_is_absent() { var knightIsAwake = true; var archerIsAwake = false; @@ -223,7 +223,7 @@ public void CannotReleasePrisonerIfOnlyKnightIsAwakeAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsPresent() + public void Cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_present() { var knightIsAwake = false; var archerIsAwake = true; @@ -233,7 +233,7 @@ public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_only_knight_is_asleep_and_pet_dog_is_absent() { var knightIsAwake = false; var archerIsAwake = true; @@ -243,7 +243,7 @@ public void CannotReleasePrisonerIfOnlyKnightIsAsleepAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CanReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsPresent() + public void Can_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_present() { var knightIsAwake = true; var archerIsAwake = false; @@ -253,7 +253,7 @@ public void CanReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_only_archer_is_asleep_and_pet_dog_is_absent() { var knightIsAwake = true; var archerIsAwake = false; @@ -263,7 +263,7 @@ public void CannotReleasePrisonerIfOnlyArcherIsAsleepAndPetDogIsAbsent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsPresent() + public void Cannot_release_prisoner_if_only_prisoner_is_asleep_and_pet_dog_is_present() { var knightIsAwake = true; var archerIsAwake = true; @@ -273,7 +273,7 @@ public void CannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsPresent() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CannotReleasePrisonerIfOnlyPrisonerIsAsleepAndPetDogIsAbsent() + public void Cannot_release_prisoner_if_only_prisoner_is_asleep_and_pet_dog_is_absent() { var knightIsAwake = true; var archerIsAwake = true; diff --git a/exercises/concept/classes/ClassesTests.cs b/exercises/concept/classes/ClassesTests.cs index e10443a57d..36a2331a64 100644 --- a/exercises/concept/classes/ClassesTests.cs +++ b/exercises/concept/classes/ClassesTests.cs @@ -3,14 +3,14 @@ public class RemoteControlCarTests { [Fact] - public void BuyNewCarReturnsInstance() + public void Buy_new_car_returns_instance() { var car = RemoteControlCar.Buy(); Assert.NotNull(car); } [Fact(Skip = "Remove this Skip property to run this test")] - public void BuyNewCarReturnsNewCarEachTime() + public void Buy_new_car_returns_new_car_each_time() { var car1 = RemoteControlCar.Buy(); var car2 = RemoteControlCar.Buy(); @@ -18,21 +18,21 @@ public void BuyNewCarReturnsNewCarEachTime() } [Fact(Skip = "Remove this Skip property to run this test")] - public void NewCarDistanceDisplay() + public void New_car_distance_display() { var car = new RemoteControlCar(); Assert.Equal("Driven 0 meters", car.DistanceDisplay()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void NewCarBatteryDisplay() + public void New_car_battery_display() { var car = new RemoteControlCar(); Assert.Equal("Battery at 100%", car.BatteryDisplay()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DistanceDisplayAfterDrivingOnce() + public void Distance_display_after_driving_once() { var car = new RemoteControlCar(); car.Drive(); @@ -40,7 +40,7 @@ public void DistanceDisplayAfterDrivingOnce() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DistanceDisplayAfterDrivingMultipleTimes() + public void Distance_display_after_driving_multiple_times() { var car = new RemoteControlCar(); @@ -53,7 +53,7 @@ public void DistanceDisplayAfterDrivingMultipleTimes() } [Fact(Skip = "Remove this Skip property to run this test")] - public void BatteryDisplayAfterDrivingOnce() + public void Battery_display_after_driving_once() { var car = new RemoteControlCar(); car.Drive(); @@ -61,7 +61,7 @@ public void BatteryDisplayAfterDrivingOnce() } [Fact(Skip = "Remove this Skip property to run this test")] - public void BatteryDisplayAfterDrivingMultipleTimes() + public void Battery_display_after_driving_multiple_times() { var car = new RemoteControlCar(); @@ -74,7 +74,7 @@ public void BatteryDisplayAfterDrivingMultipleTimes() } [Fact(Skip = "Remove this Skip property to run this test")] - public void BatteryDisplayWhenBatteryEmpty() + public void Battery_display_when_battery_empty() { var car = new RemoteControlCar(); @@ -91,7 +91,7 @@ public void BatteryDisplayWhenBatteryEmpty() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DistanceDisplayWhenBatteryEmpty() + public void Distance_display_when_battery_empty() { var car = new RemoteControlCar(); diff --git a/exercises/concept/constructors/ConstructorsTests.cs b/exercises/concept/constructors/ConstructorsTests.cs index f4de32b035..e19951519b 100644 --- a/exercises/concept/constructors/ConstructorsTests.cs +++ b/exercises/concept/constructors/ConstructorsTests.cs @@ -3,7 +3,7 @@ public class RemoteControlCarTests { [Fact] - public void NewRemoteControlCarHasNotDrivenAnyDistance() + public void New_remote_control_car_has_not_driven_any_distance() { int speed = 10; int batteryDrain = 2; @@ -13,7 +13,7 @@ public void NewRemoteControlCarHasNotDrivenAnyDistance() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DriveIncreasesDistanceDrivenWithSpeed() + public void Drive_increases_distance_driven_with_speed() { int speed = 5; int batteryDrain = 1; @@ -25,7 +25,7 @@ public void DriveIncreasesDistanceDrivenWithSpeed() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DriveDoesNotIncreaseDistanceDrivenWhenBatteryDrained() + public void Drive_does_not_increase_distance_driven_when_battery_drained() { int speed = 9; int batteryDrain = 50; @@ -42,7 +42,7 @@ public void DriveDoesNotIncreaseDistanceDrivenWhenBatteryDrained() } [Fact(Skip = "Remove this Skip property to run this test")] - public void NewRemoteControlCarBatteryIsNotDrained() + public void New_remote_control_car_battery_is_not_drained() { int speed = 15; int batteryDrain = 3; @@ -52,7 +52,7 @@ public void NewRemoteControlCarBatteryIsNotDrained() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DriveToAlmostDrainBattery() + public void Drive_to_almost_drain_battery() { int speed = 2; int batteryDrain = 1; @@ -68,7 +68,7 @@ public void DriveToAlmostDrainBattery() } [Fact(Skip = "Remove this Skip property to run this test")] - public void DriveUntilBatteryIsDrained() + public void Drive_until_battery_is_drained() { int speed = 2; int batteryDrain = 1; @@ -84,21 +84,21 @@ public void DriveUntilBatteryIsDrained() } [Fact(Skip = "Remove this Skip property to run this test")] - public void TopOfTheLineCarHasNotDrivenAnyDistance() + public void Top_of_the_line_car_has_not_driven_any_distance() { var car = RemoteControlCar.TopOfTheLine(); Assert.Equal(0, car.DistanceDriven()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TopOfTheLineCarHasBatteryNotDrained() + public void Top_of_the_line_car_has_battery_not_drained() { var car = RemoteControlCar.TopOfTheLine(); Assert.False(car.BatteryDrained()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TopOfTheLineCarHasCorrectSpeed() + public void Top_of_the_line_car_has_correct_speed() { var car = RemoteControlCar.TopOfTheLine(); car.Drive(); @@ -106,7 +106,7 @@ public void TopOfTheLineCarHasCorrectSpeed() } [Fact(Skip = "Remove this Skip property to run this test")] - public void TopOfTheLineHasCorrectBatteryDrain() + public void Top_of_the_line_has_correct_battery_drain() { var car = RemoteControlCar.TopOfTheLine(); @@ -128,7 +128,7 @@ public void TopOfTheLineHasCorrectBatteryDrain() public class RaceTrackTests { [Fact(Skip = "Remove this Skip property to run this test")] - public void CarCanFinishWithCarThatCanEasilyFinish() + public void Car_can_finish_with_car_that_can_easily_finish() { int speed = 10; int batteryDrain = 2; @@ -141,7 +141,7 @@ public void CarCanFinishWithCarThatCanEasilyFinish() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CarCanFinishWithCarThatCanJustFinish() + public void Car_can_finish_with_car_that_can_just_finish() { int speed = 2; int batteryDrain = 10; @@ -154,7 +154,7 @@ public void CarCanFinishWithCarThatCanJustFinish() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CarCanFinishWithCarThatJustCannotFinish() + public void Car_can_finish_with_car_that_just_cannot_finish() { int speed = 3; int batteryDrain = 20; @@ -167,7 +167,7 @@ public void CarCanFinishWithCarThatJustCannotFinish() } [Fact(Skip = "Remove this Skip property to run this test")] - public void CarCanFinishWithCarThatCannotFinish() + public void Car_can_finish_with_car_that_cannot_finish() { int speed = 1; int batteryDrain = 20; diff --git a/exercises/concept/datetimes/DateTimesTests.cs b/exercises/concept/datetimes/DateTimesTests.cs index 8a0adf672d..d41d385a78 100644 --- a/exercises/concept/datetimes/DateTimesTests.cs +++ b/exercises/concept/datetimes/DateTimesTests.cs @@ -9,151 +9,151 @@ public class AppointmentTests { [Fact] - public void ScheduleDateUsingOnlyNumbers() + public void Schedule_date_using_only_numbers() { Assert.Equal(new DateTime(2019, 07, 25, 13, 45, 0), Appointment.Schedule("7/25/2019 13:45:00")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ScheduleDateWithTextualMonth() + public void Schedule_date_with_textual_month() { Assert.Equal(new DateTime(2019, 6, 3, 11, 30, 0), Appointment.Schedule("June 3, 2019 11:30:00")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ScheduleDateWithTextualMonthAndWeekday() + public void Schedule_date_with_textual_month_and_weekday() { Assert.Equal(new DateTime(2019, 12, 5, 9, 0, 0), Appointment.Schedule("Thursday, December 5, 2019 09:00:00")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentOneYearAgo() + public void Has_passed_with_appointment_one_year_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddYears(-1).AddHours(2))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentMonthsAgo() + public void Has_passed_with_appointment_months_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddMonths(-8))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentDaysAgo() + public void Has_passed_with_appointment_days_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddDays(-23))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentHoursAgo() + public void Has_passed_with_appointment_hours_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddHours(-12))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentMinutesAgo() + public void Has_passed_with_appointment_minutes_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-55))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentOneMinuteAgo() + public void Has_passed_with_appointment_one_minute_ago() { Assert.True(Appointment.HasPassed(DateTime.Now.AddMinutes(-1))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInOneMinute() + public void Has_passed_with_appointment_in_one_minute() { Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(1))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInMinutes() + public void Has_passed_with_appointment_in_minutes() { Assert.False(Appointment.HasPassed(DateTime.Now.AddMinutes(5))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInDays() + public void Has_passed_with_appointment_in_days() { Assert.False(Appointment.HasPassed(DateTime.Now.AddDays(19))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInMonths() + public void Has_passed_with_appointment_in_months() { Assert.False(Appointment.HasPassed(DateTime.Now.AddMonths(10))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void HasPassedWithAppointmentInYears() + public void Has_passed_with_appointment_in_years() { Assert.False(Appointment.HasPassed(DateTime.Now.AddYears(2).AddMonths(3).AddDays(6))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyMorningAppointment() + public void Is_afternoon_appointment_for_early_morning_appointment() { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 6, 17, 8, 15, 0))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateMorningAppointment() + public void Is_afternoon_appointment_for_late_morning_appointment() { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 2, 23, 11, 59, 59))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForNoonAppointment() + public void Is_afternoon_appointment_for_noon_appointment() { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 0))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyAfternoonAppointment() + public void Is_afternoon_appointment_for_early_afternoon_appointment() { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 8, 9, 12, 0, 1))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateAfternoonAppointment() + public void Is_afternoon_appointment_for_late_afternoon_appointment() { Assert.True(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 17, 59, 59))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForEarlyEveningAppointment() + public void Is_afternoon_appointment_for_early_evening_appointment() { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 18, 0, 0))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void IsAfternoonAppointmentForLateEveningAppointment() + public void Is_afternoon_appointment_for_late_evening_appointment() { Assert.False(Appointment.IsAfternoonAppointment(new DateTime(2019, 9, 1, 23, 59, 59))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnFridayAfternoon() + public void Description_on_friday_afternoon() { Assert.Equal("You have an appointment on 3/29/2019 3:00:00 PM.", Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnThursdayAfternoon() + public void Description_on_thursday_afternoon() { Assert.Equal("You have an appointment on 7/25/2019 1:45:00 PM.", Appointment.Description(new DateTime(2019, 07, 25, 13, 45, 0))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DescriptionOnWednesdayMorning() + public void Description_on_wednesday_morning() { Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9))); } [Fact] - public void AnniversaryDate() + public void Anniversary_date() { Assert.Equal(new DateTime(DateTime.Now.Year, 9, 15), Appointment.AnniversaryDate()); } diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/enums/EnumsTests.cs index d982873fe0..272e4ab229 100644 --- a/exercises/concept/enums/EnumsTests.cs +++ b/exercises/concept/enums/EnumsTests.cs @@ -3,85 +3,85 @@ public class LogLineTests { [Fact] - public void ParseTrace() + public void Parse_trace() { Assert.Equal(LogLevel.Trace, LogLine.ParseLogLevel("[TRC]: Line 84 - Console.WriteLine('Hello World');")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseDebug() + public void Parse_debug() { Assert.Equal(LogLevel.Debug, LogLine.ParseLogLevel("[DBG]: ; expected")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseInfo() + public void Parse_info() { Assert.Equal(LogLevel.Info, LogLine.ParseLogLevel("[INF]: Timezone changed")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseWarning() + public void Parse_warning() { Assert.Equal(LogLevel.Warning, LogLine.ParseLogLevel("[WRN]: Timezone not set")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseError() + public void Parse_error() { Assert.Equal(LogLevel.Error, LogLine.ParseLogLevel("[ERR]: Disk full")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseFatal() + public void Parse_fatal() { Assert.Equal(LogLevel.Fatal, LogLine.ParseLogLevel("[FTL]: Not enough memory")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ParseUnknown() + public void Parse_unknown() { Assert.Equal(LogLevel.Unknown, LogLine.ParseLogLevel("[XYZ]: Gibberish message.. beep boop..")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForTrace() + public void Output_for_short_log_for_trace() { Assert.Equal("0:Line 13 - int myNum = 42;", LogLine.OutputForShortLog(LogLevel.Trace, "Line 13 - int myNum = 42;")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForDebug() + public void Output_for_short_log_for_debug() { Assert.Equal("1:The name 'LogLevel' does not exist in the current context", LogLine.OutputForShortLog(LogLevel.Debug, "The name 'LogLevel' does not exist in the current context")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForInfo() + public void Output_for_short_log_for_info() { Assert.Equal("4:File moved", LogLine.OutputForShortLog(LogLevel.Info, "File moved")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForWarning() + public void Output_for_short_log_for_warning() { Assert.Equal("5:Unsafe password", LogLine.OutputForShortLog(LogLevel.Warning, "Unsafe password")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForError() + public void Output_for_short_log_for_error() { Assert.Equal("6:Stack overflow", LogLine.OutputForShortLog(LogLevel.Error, "Stack overflow")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForFatal() + public void Output_for_short_log_for_fatal() { Assert.Equal("7:Dumping all files", LogLine.OutputForShortLog(LogLevel.Fatal, "Dumping all files")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OutputForShortLogForUnknown() + public void Output_for_short_log_for_unknown() { Assert.Equal("42:Something unknown happened", LogLine.OutputForShortLog(LogLevel.Unknown, "Something unknown happened")); } diff --git a/exercises/concept/flag-enums/FlagEnumsTests.cs b/exercises/concept/flag-enums/FlagEnumsTests.cs index d8f653c9b6..3646faba13 100644 --- a/exercises/concept/flag-enums/FlagEnumsTests.cs +++ b/exercises/concept/flag-enums/FlagEnumsTests.cs @@ -3,133 +3,133 @@ public class PermissionsTests { [Fact] - public void DefaultForGuest() + public void Default_for_guest() { Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForUser() + public void Default_for_user() { Assert.Equal(Permission.Read | Permission.Write, Permissions.Default(AccountType.User)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForModerator() + public void Default_for_moderator() { Assert.Equal(Permission.Read | Permission.Write | Permission.Delete, Permissions.Default(AccountType.Moderator)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void DefaultForUnknown() + public void Default_for_unknown() { Assert.Equal(Permission.None, Permissions.Default((AccountType)123)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadToNone() + public void Grant_read_to_none() { Assert.Equal(Permission.Read, Permissions.Grant(Permission.None, Permission.Read)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadToRead() + public void Grant_read_to_read() { Assert.Equal(Permission.Read, Permissions.Grant(Permission.Read, Permission.Read)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantAllToNone() + public void Grant_all_to_none() { Assert.Equal(Permission.All, Permissions.Grant(Permission.None, Permission.All)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantDeleteToReadAndWrite() + public void Grant_delete_to_read_and_write() { Assert.Equal(Permission.All, Permissions.Grant(Permission.Read | Permission.Write, Permission.Delete)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void GrantReadAndWriteToNone() + public void Grant_read_and_write_to_none() { Assert.Equal(Permission.Read | Permission.Write, Permissions.Grant(Permission.None, Permission.Read | Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeNoneFromRead() + public void Revoke_none_from_read() { Assert.Equal(Permission.Read, Permissions.Revoke(Permission.Read, Permission.None)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeWriteFromWrite() + public void Revoke_write_from_write() { Assert.Equal(Permission.None, Permissions.Revoke(Permission.Write, Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeDeleteFromAll() + public void Revoke_delete_from_all() { Assert.Equal(Permission.Read | Permission.Write, Permissions.Revoke(Permission.All, Permission.Delete)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeReadAndWriteFromWriteAndDelete() + public void Revoke_read_and_write_from_write_and_delete() { Assert.Equal(Permission.Delete, Permissions.Revoke(Permission.Write | Permission.Delete, Permission.Read | Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RevokeAllFromReadAndWrite() + public void Revoke_all_from_read_and_write() { Assert.Equal(Permission.None, Permissions.Revoke(Permission.Read | Permission.Write, Permission.All)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckNoneForRead() + public void Check_none_for_read() { Assert.False(Permissions.Check(Permission.None, Permission.Read)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckWriteForWrite() + public void Check_write_for_write() { Assert.True(Permissions.Check(Permission.Write, Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckAllForWrite() + public void Check_all_for_write() { Assert.True(Permissions.Check(Permission.All, Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForRead() + public void Check_read_and_write_for_read() { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckAllForReadAndWrite() + public void Check_all_for_read_and_write() { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForReadAndWrite() + public void Check_read_and_write_for_read_and_write() { Assert.True(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Write)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteForReadAndDelete() + public void Check_read_and_write_for_read_and_delete() { Assert.False(Permissions.Check(Permission.Read | Permission.Write, Permission.Read | Permission.Delete)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void CheckReadAndWriteAndDeleteForAll() + public void Check_read_and_write_and_delete_for_all() { Assert.True(Permissions.Check(Permission.Read | Permission.Write | Permission.Delete, Permission.All)); } diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs index 2786f06d0e..815f60c5b0 100644 --- a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs +++ b/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs @@ -3,145 +3,145 @@ public class SavingsAccountTests { [Fact] - public void MinimalFirstInterestRate() + public void Minimal_first_interest_rate() { Assert.Equal(0.5f, SavingsAccount.InterestRate(0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinyFirstInterestRate() + public void Tiny_first_interest_rate() { Assert.Equal(0.5f, SavingsAccount.InterestRate(0.000001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MaximumFirstInterestRate() + public void Maximum_first_interest_rate() { Assert.Equal(0.5f, SavingsAccount.InterestRate(999.9999m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalSecondInterestRate() + public void Minimal_second_interest_rate() { Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinySecondInterestRate() + public void Tiny_second_interest_rate() { Assert.Equal(1.621f, SavingsAccount.InterestRate(1_000.0001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MaximumSecondInterestRate() + public void Maximum_second_interest_rate() { Assert.Equal(1.621f, SavingsAccount.InterestRate(4_999.9990m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalThirdInterestRate() + public void Minimal_third_interest_rate() { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0000m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void TinyThirdInterestRate() + public void Tiny_third_interest_rate() { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_000.0001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void LargeThirdInterestRate() + public void Large_third_interest_rate() { Assert.Equal(2.475f, SavingsAccount.InterestRate(5_639_998.742909m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MinimalNegativeInterestRate() + public void Minimal_negative_interest_rate() { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.000001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void SmallNegativeInterestRate() + public void Small_negative_interest_rate() { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-0.123m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void RegularNegativeInterestRate() + public void Regular_negative_interest_rate() { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-300.0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void LargeNegativeInterestRate() + public void Large_negative_interest_rate() { Assert.Equal(-3.213f, SavingsAccount.InterestRate(-152964.231m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForEmptyStartBalance() + public void Annual_balance_update_for_empty_start_balance() { Assert.Equal(0.0000m, SavingsAccount.AnnualBalanceUpdate(0.0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForSmallPositiveStartBalance() + public void Annual_balance_update_for_small_positive_start_balance() { Assert.Equal(0.000001005m, SavingsAccount.AnnualBalanceUpdate(0.000001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForAveragePositiveStartBalance() + public void Annual_balance_update_for_average_positive_start_balance() { Assert.Equal(1016.210000m, SavingsAccount.AnnualBalanceUpdate(1_000.0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForLargePositiveStartBalance() + public void Annual_balance_update_for_large_positive_start_balance() { Assert.Equal(1016.210101621m, SavingsAccount.AnnualBalanceUpdate(1_000.0001m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForHugePositiveStartBalance() + public void Annual_balance_update_for_huge_positive_start_balance() { Assert.Equal(920352587.26744292868451875m, SavingsAccount.AnnualBalanceUpdate(898124017.826243404425m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForSmallNegativeStartBalance() + public void Annual_balance_update_for_small_negative_start_balance() { Assert.Equal(-0.12695199m, SavingsAccount.AnnualBalanceUpdate(-0.123m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void AnnualBalanceUpdateForLargeNegativeStartBalance() + public void Annual_balance_update_for_large_negative_start_balance() { Assert.Equal(-157878.97174203m, SavingsAccount.AnnualBalanceUpdate(-152964.231m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForSmallStartBalance() + public void Years_before_desired_balance_for_small_start_balance() { Assert.Equal(47, SavingsAccount.YearsBeforeDesiredBalance(100.0m, 125.80m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForAverageStartBalance() + public void Years_before_desired_balance_for_average_start_balance() { Assert.Equal(6, SavingsAccount.YearsBeforeDesiredBalance(1_000.0m, 1_100.0m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForLargeStartBalance() + public void Years_before_desired_balance_for_large_start_balance() { Assert.Equal(5, SavingsAccount.YearsBeforeDesiredBalance(8_080.80m, 9_090.90m)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void YearsBeforeDesiredBalanceForLargeDifferentBetweenStartAndTargetBalance() + public void Years_before_desired_balance_for_large_different_between_start_and_target_balance() { Assert.Equal(85, SavingsAccount.YearsBeforeDesiredBalance(2_345.67m, 12_345.6789m)); } diff --git a/exercises/concept/nullability/NullabilityTests.cs b/exercises/concept/nullability/NullabilityTests.cs index cab573b8f4..3379eccc2d 100644 --- a/exercises/concept/nullability/NullabilityTests.cs +++ b/exercises/concept/nullability/NullabilityTests.cs @@ -3,25 +3,25 @@ public class NullabilityTests { [Fact] - public void LabelForEmployee() + public void Label_for_employee() { Assert.Equal("[17] Ryder Herbert - MARKETING", Badge.Print(17, "Ryder Herbert", "Marketing")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void LabelForNewEmployee() + public void Label_for_new_employee() { Assert.Equal("Bogdan Rosario - MARKETING", Badge.Print(null, "Bogdan Rosario", "Marketing")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void LabelForOwner() + public void Label_for_owner() { Assert.Equal("[59] Julie Sokato - OWNER", Badge.Print(59, "Julie Sokato", null)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void LabelForNewOwner() + public void Label_for_new_owner() { Assert.Equal("Amare Osei - OWNER", Badge.Print(null, "Amare Osei", null)); } diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/numbers/NumbersTests.cs index d8aad5b748..fb219ac2dc 100644 --- a/exercises/concept/numbers/NumbersTests.cs +++ b/exercises/concept/numbers/NumbersTests.cs @@ -3,73 +3,73 @@ public class AssemblyLineTests { [Fact] - public void ProductionRatePerHourForSpeedZero() + public void Production_rate_per_hour_for_speed_zero() { Assert.Equal(0.0, AssemblyLine.ProductionRatePerHour(0)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedOne() + public void Production_rate_per_hour_for_speed_one() { Assert.Equal(221.0, AssemblyLine.ProductionRatePerHour(1)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedFour() + public void Production_rate_per_hour_for_speed_four() { Assert.Equal(884.0, AssemblyLine.ProductionRatePerHour(4)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedSeven() + public void Production_rate_per_hour_for_speed_seven() { Assert.Equal(1392.3, AssemblyLine.ProductionRatePerHour(7)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedNine() + public void Production_rate_per_hour_for_speed_nine() { Assert.Equal(1591.2, AssemblyLine.ProductionRatePerHour(9)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ProductionRatePerHourForSpeedTen() + public void Production_rate_per_hour_for_speed_ten() { Assert.Equal(1701.7, AssemblyLine.ProductionRatePerHour(10)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedZero() + public void Working_items_per_minute_for_speed_zero() { Assert.Equal(0, AssemblyLine.WorkingItemsPerMinute(0)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedOne() + public void Working_items_per_minute_for_speed_one() { Assert.Equal(3, AssemblyLine.WorkingItemsPerMinute(1)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedFive() + public void Working_items_per_minute_for_speed_five() { Assert.Equal(16, AssemblyLine.WorkingItemsPerMinute(5)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedEight() + public void Working_items_per_minute_for_speed_eight() { Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(8)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedNine() + public void Working_items_per_minute_for_speed_nine() { Assert.Equal(26, AssemblyLine.WorkingItemsPerMinute(9)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WorkingItemsPerMinuteForSpeedTen() + public void Working_items_per_minute_for_speed_ten() { Assert.Equal(28, AssemblyLine.WorkingItemsPerMinute(10)); } diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/properties/PropertiesTests.cs index 978ba1e23c..3df1c6bb83 100644 --- a/exercises/concept/properties/PropertiesTests.cs +++ b/exercises/concept/properties/PropertiesTests.cs @@ -19,7 +19,7 @@ public void Negative_weight_is_invalid() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Get_US_display_weight() + public void Get_us_display_weight() { var wm = new WeighingMachine(); wm.InputWeight = 60m; @@ -27,7 +27,7 @@ public void Get_US_display_weight() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Input_pounds_and_get_US_display_weight() + public void Input_pounds_and_get_us_display_weight() { var wm = new WeighingMachine(); wm.Units = Units.Pounds; diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/strings/StringsTests.cs index 91a376001a..ad78688be0 100644 --- a/exercises/concept/strings/StringsTests.cs +++ b/exercises/concept/strings/StringsTests.cs @@ -3,67 +3,67 @@ public class LogLineTests { [Fact] - public void ErrorMessage() + public void Error_message() { Assert.Equal("Stack overflow", LogLine.Message("[ERROR]: Stack overflow")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningMessage() + public void Warning_message() { Assert.Equal("Disk almost full", LogLine.Message("[WARNING]: Disk almost full")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoMessage() + public void Info_message() { Assert.Equal("File moved", LogLine.Message("[INFO]: File moved")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void MessageWithLeadingAndTrailingWhiteSpace() + public void Message_with_leading_and_trailing_white_space() { Assert.Equal("Timezone not set", LogLine.Message("[WARNING]: \tTimezone not set \r\n")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ErrorLogLevel() + public void Error_log_level() { Assert.Equal("error", LogLine.LogLevel("[ERROR]: Disk full")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningLogLevel() + public void Warning_log_level() { Assert.Equal("warning", LogLine.LogLevel("[WARNING]: Unsafe password")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoLogLevel() + public void Info_log_level() { Assert.Equal("info", LogLine.LogLevel("[INFO]: Timezone changed")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ErrorReformat() + public void Error_reformat() { Assert.Equal("Segmentation fault (error)", LogLine.Reformat("[ERROR]: Segmentation fault")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void WarningReformat() + public void Warning_reformat() { Assert.Equal("Decreased performance (warning)", LogLine.Reformat("[WARNING]: Decreased performance")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void InfoReformat() + public void Info_reformat() { Assert.Equal("Disk defragmented (info)", LogLine.Reformat("[INFO]: Disk defragmented")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void ReformatWithLeadingAndTrailingWhiteSpace() + public void Reformat_with_leading_and_trailing_white_space() { Assert.Equal("Corrupt disk (error)", LogLine.Reformat("[ERROR]: \t Corrupt disk\t \t \r\n")); } diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index c1d3fd2f9d..6de2d56abb 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -62,6 +62,7 @@ For more information, please read [this in-depth description][stub-file], [watch - [xUnit][xunit] is used as the test framework. - Only use `Fact` tests; don't use `Theory` tests. - All but the first test should be skipped by default (check [this example][skip-fact]). +- Test methods should be named using `snake_case`, with the first character uppercased (check [this example][test-name]). For more information, please read [this in-depth description][tests-file], [watch this video][video-tests-file] and check [this example tests file][example-tests-file]. @@ -142,6 +143,7 @@ If you have any questions regarding implementing the exercise, please post them [example-example-file]: ../exercises/concept/strings/.meta/Example.cs [example-project-file]: ../exercises/concept/strings/Strings.csproj [skip-fact]: ../exercises/concept/strings/StringsTests.cs#L11 +[test-name]: ../exercises/concept/strings/StringsTests.cs#L24 [xunit]: https://xunit.net/ [not-implemented-static]: ../exercises/concept/arrays/Arrays.cs#L12 [not-implemented]: ../exercises/concept/arrays/Arrays.cs#L17 From 8ed37e1dc3c0b6f7e9d135e97d424ee1116f86aa Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 19 May 2020 09:16:35 +0200 Subject: [PATCH 129/327] Use basic syntax --- exercises/concept/properties/.meta/Example.cs | 20 +++++++++++++-- .../concept/properties/PropertiesTests.cs | 25 ++++++++++++++++--- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/exercises/concept/properties/.meta/Example.cs b/exercises/concept/properties/.meta/Example.cs index 03ca66c52a..6010defd08 100644 --- a/exercises/concept/properties/.meta/Example.cs +++ b/exercises/concept/properties/.meta/Example.cs @@ -9,6 +9,7 @@ enum Units class WeighingMachine { private const decimal POUNDS_PER_KILOGRAM = 2.20462m; + private decimal inputWeight; public Units Units { get; set; } = Units.Kilograms; @@ -37,6 +38,7 @@ public decimal DisplayWeight return ApplyTareAdjustment(inputWeight); } } + public USWeight USDisplayWeight { get @@ -44,9 +46,23 @@ public USWeight USDisplayWeight return new USWeight(WeightInPounds(DisplayWeight)); } } + public decimal TareAdjustment { set; private get; } - private decimal ApplyTareAdjustment(decimal weight) => weight - TareAdjustment; - private decimal WeightInPounds(decimal weight) => Units == Units.Kilograms ? weight * POUNDS_PER_KILOGRAM : weight; + + private decimal ApplyTareAdjustment(decimal weight) + { + return weight - TareAdjustment; + } + + private decimal WeightInPounds(decimal weight) + { + if (Units == Units.Kilograms) + { + return weight * POUNDS_PER_KILOGRAM; + } + + return weight; + } } class USWeight diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/properties/PropertiesTests.cs index 3df1c6bb83..88568c2877 100644 --- a/exercises/concept/properties/PropertiesTests.cs +++ b/exercises/concept/properties/PropertiesTests.cs @@ -19,20 +19,37 @@ public void Negative_weight_is_invalid() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Get_us_display_weight() + public void Get_us_display_weight_pounds() { var wm = new WeighingMachine(); wm.InputWeight = 60m; - Assert.Equal((132, 4), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); + Assert.Equal(132, wm.USDisplayWeight.Pounds); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Input_pounds_and_get_us_display_weight() + public void Get_us_display_weight_ounces() + { + var wm = new WeighingMachine(); + wm.InputWeight = 60m; + Assert.Equal(4, wm.USDisplayWeight.Ounces); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Input_pounds_and_get_us_display_weight_pounds() + { + var wm = new WeighingMachine(); + wm.Units = Units.Pounds; + wm.InputWeight = 175.5m; + Assert.Equal(175, wm.USDisplayWeight.Pounds); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Input_pounds_and_get_is_display_weight_ounces() { var wm = new WeighingMachine(); wm.Units = Units.Pounds; wm.InputWeight = 175.5m; - Assert.Equal((175, 8), (wm.USDisplayWeight.Pounds, wm.USDisplayWeight.Ounces)); + Assert.Equal(8, wm.USDisplayWeight.Ounces); } [Fact(Skip = "Remove this Skip property to run this test")] From 9ad600febeaa61c994a7489bda42f80cf7983eb8 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 19 May 2020 09:59:39 +0200 Subject: [PATCH 130/327] Add mutation [Arrays] Add mutation --- exercises/concept/arrays/.docs/hints.md | 20 ++++---- .../concept/arrays/.docs/instructions.md | 48 ++++++++++++------- exercises/concept/arrays/.meta/Example.cs | 35 ++++++++------ exercises/concept/arrays/.meta/design.md | 3 +- exercises/concept/arrays/Arrays.cs | 19 +++++--- exercises/concept/arrays/ArraysTests.cs | 46 +++++++++++++++--- 6 files changed, 116 insertions(+), 55 deletions(-) diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/arrays/.docs/hints.md index 372b0f00df..4deaab12e2 100644 --- a/exercises/concept/arrays/.docs/hints.md +++ b/exercises/concept/arrays/.docs/hints.md @@ -8,28 +8,32 @@ - As this method does _not_ depend on the current week's count, it is defined as a [`static` method][static-members]. - There are [several ways to define an array][single-dimensional-arrays]. -### 2. Check how many birds visited yesterday +### 2. Check how many birds visited today - Remember that the counts are ordered by day from oldest to most recent, with the last element representing today. -- Accessing the second last element can be done either by using its (fixed) index (remember to start counting from zero) or by calculating its index using the [array's size][array-length]. +- Accessing the last element can be done either by using its (fixed) index (remember to start counting from zero) or by calculating its index using the [array's size][array-length]. -### 3. Calculate the total number of visiting birds +### 3. Increment today's count + +- Set the element representing today's count to today's count plus 1. + +### 4. Check if there was a day with no visiting birds + +- The `Array` class has a [built-in method][array-indexof] that returns the first index where the element is found, or -1 if no matching element was found. + +### 5. Calculate the total number of visiting birds - A variable can be used to hold the total number of visiting birds. - The array can be iterated over using a [`foreach` loop][array-foreach]. - The variable can be updated inside the loop. -### 4. Calculate the number of busy days +### 6. Calculate the number of busy days - A variable can be used to hold the number of busy days. - The array can be iterated over using a [`foreach` loop][array-foreach]. - The variable can be updated inside the loop. - A [conditional statement][if-statement] can be used inside the loop. -### 5. Check if there was a day with no visiting birds - -- The `Array` class has a [built-in method][array-indexof] to check at which index an element can be found. A special value is returned if a matching element could not be found. - [array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays [single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays [fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md index 2a2794c18e..f9d41d42b6 100644 --- a/exercises/concept/arrays/.docs/instructions.md +++ b/exercises/concept/arrays/.docs/instructions.md @@ -1,6 +1,6 @@ You're an avid bird watcher that keeps track of how many birds have visited your garden in the last seven days. -You have five tasks, all dealing with the numbers of birds that visited your garden. +You have six tasks, all dealing with the numbers of birds that visited your garden. ### 1. Check what the counts were last week @@ -11,47 +11,59 @@ BirdCount.LastWeek(); // => [0, 2, 5, 3, 7, 8, 4] ``` -### 2. Check how many birds visited yesterday +### 2. Check how many birds visited today -Implement the `BirdCount.Yesterday()` method to return how many birds visited your garden yesterday. The bird counts are ordered by day, with the first element being the count of the oldest day, and the last element being today's count. +Implement the `BirdCount.Today()` method to return how many birds visited your garden today. The bird counts are ordered by day, with the first element being the count of the oldest day, and the last element being today's count. ```csharp int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; var birdCount = new BirdCount(birdsPerDay); -birdCount.Yesterday(); -// => 4 +birdCount.Today(); +// => 1 ``` -### 3. Calculate the total number of visiting birds +### 3. Increment today's count -Implement the `BirdCount.Total()` method to return the total number of birds that have visited your garden: +Implement the `BirdCount.IncrementDayCount()` method to increment today's count: ```csharp int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; var birdCount = new BirdCount(birdsPerDay); -birdCount.Total(); -// => 19 +birdCount.IncrementDayCount(); +birdCount.Today(); +// => 2 ``` -### 4. Calculate the number of busy days +### 4. Check if there was a day with no visiting birds -Some days are busier that others. A busy day is one where five or more birds have visited your garden. -Implement the `BirdCount.BusyDays()` method to return the number of busy days: +Implement the `BirdCount.HasDayWithoutBirds()` method that returns `true` if there was a day at which zero birds visited the garden; otherwise, return `false`: ```csharp int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; var birdCount = new BirdCount(birdsPerDay); -birdCount.BusyDays(); -// => 2 +birdCount.HasDayWithoutBirds(); +// => true ``` -### 5. Check if there was a day with no visiting birds +### 5. Calculate the total number of visiting birds -Implement the `BirdCount.HasDayWithoutBirds()` method that returns `true` if there was a day at which zero birds visited the garden; otherwise, return `false`: +Implement the `BirdCount.Total()` method to return the total number of birds that have visited your garden: ```csharp int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; var birdCount = new BirdCount(birdsPerDay); -birdCount.HasDayWithoutBirds(); -// => true +birdCount.Total(); +// => 19 +``` + +### 6. Calculate the number of busy days + +Some days are busier that others. A busy day is one where five or more birds have visited your garden. +Implement the `BirdCount.BusyDays()` method to return the number of busy days: + +```csharp +int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; +var birdCount = new BirdCount(birdsPerDay); +birdCount.BusyDays(); +// => 2 ``` diff --git a/exercises/concept/arrays/.meta/Example.cs b/exercises/concept/arrays/.meta/Example.cs index 78e31c6788..d2e947c966 100644 --- a/exercises/concept/arrays/.meta/Example.cs +++ b/exercises/concept/arrays/.meta/Example.cs @@ -9,6 +9,26 @@ public BirdCount(int[] birdsPerDay) this.birdsPerDay = birdsPerDay; } + public static int[] LastWeek() + { + return new int[] { 0, 2, 5, 3, 7, 8, 4 }; + } + + public int Today() + { + return birdsPerDay[6]; + } + + public void IncrementTodaysCount() + { + birdsPerDay[6]++; + } + + public bool HasDayWithoutBirds() + { + return Array.IndexOf(birdsPerDay, 0) != -1; + } + public int Total() { var total = 0; @@ -35,19 +55,4 @@ public int BusyDays() return days; } - - public int Yesterday() - { - return birdsPerDay[5]; - } - - public bool HasDayWithoutBirds() - { - return Array.IndexOf(birdsPerDay, 0) != -1; - } - - public static int[] LastWeek() - { - return new int[] { 0, 2, 5, 3, 7, 8, 4 }; - } } diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index c8f9226dcb..39aa42e300 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -16,6 +16,7 @@ Of the many available C# collection types, we chose to use the `array` collectio - The existence of the `Array` type. - Defining an array. - Accessing elements in an array by index. +- Updating an element in an array by index. - Iterating over elements in an array. - Basic array functions (like finding the index of an element in an array). @@ -31,7 +32,7 @@ Of the many available C# collection types, we chose to use the `array` collectio This Concepts Exercise's Concepts are: -- `arrays`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). +- `arrays`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to update an element in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). - `foreach-loops`: know how to iterate over a collection. ## Prequisites diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/arrays/Arrays.cs index d3cecb89af..bfb04d17c0 100644 --- a/exercises/concept/arrays/Arrays.cs +++ b/exercises/concept/arrays/Arrays.cs @@ -14,9 +14,19 @@ public static int[] LastWeek() throw new NotImplementedException("Please implement the (static) BirdCount.LastWeek() method"); } - public int Yesterday() + public int Today() { - throw new NotImplementedException("Please implement the BirdCount.Yesterday() method"); + throw new NotImplementedException("Please implement the BirdCount.Today() method"); + } + + public int IncrementTodaysCount() + { + throw new NotImplementedException("Please implement the BirdCount.IncrementTodaysCount() method"); + } + + public bool HasDayWithoutBirds() + { + throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds() method"); } public int Total() @@ -28,9 +38,4 @@ public int BusyDays() { throw new NotImplementedException("Please implement the BirdCount.BusyDays() method"); } - - public bool HasDayWithoutBirds() - { - throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds() method"); - } } diff --git a/exercises/concept/arrays/ArraysTests.cs b/exercises/concept/arrays/ArraysTests.cs index 4ca20a88ea..697cca5293 100644 --- a/exercises/concept/arrays/ArraysTests.cs +++ b/exercises/concept/arrays/ArraysTests.cs @@ -2,29 +2,63 @@ public class BirdCountTests { - [Fact(Skip = "Remove this Skip property to run this test")] + [Fact] public void Last_week() { Assert.Equal(new int[] { 0, 2, 5, 3, 7, 8, 4 }, BirdCount.LastWeek()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Yesterday_for_disappointing_week() + public void Today_for_disappointing_day() { var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; var birdCount = new BirdCount(counts); - Assert.Equal(1, birdCount.Yesterday()); + Assert.Equal(0, birdCount.Today()); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Yesterday_days_for_busy_week() + public void Today_for_busy_day() { var counts = new int[] { 8, 8, 9, 5, 4, 7, 10 }; var birdCount = new BirdCount(counts); - Assert.Equal(7, birdCount.Yesterday()); + Assert.Equal(10, birdCount.Today()); } - [Fact] + [Fact(Skip = "Remove this Skip property to run this test")] + public void Has_day_without_birds_with_day_without_birds() + { + var counts = new int[] { 5, 5, 4, 0, 7, 6, 7 }; + var birdCount = new BirdCount(counts); + Assert.True(birdCount.HasDayWithoutBirds()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Has_day_without_birds_with_no_day_without_birds() + { + var counts = new int[] { 4, 5, 9, 10, 9, 4, 3 }; + var birdCount = new BirdCount(counts); + Assert.False(birdCount.HasDayWithoutBirds()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Increment_todays_count_with_no_previous_visits() + { + var counts = new int[] { 0, 0, 0, 4, 2, 3, 0 }; + var birdCount = new BirdCount(counts); + birdCount.IncrementTodaysCount(); + Assert.Equal(1, birdCount.Today()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Increment_todays_count_with_multiple_previous_visits() + { + var counts = new int[] { 8, 8, 9, 2, 1, 6, 4 }; + var birdCount = new BirdCount(counts); + birdCount.IncrementTodaysCount(); + Assert.Equal(5, birdCount.Today()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] public void Total_for_disappointing_week() { var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; From 3ed42b7db7709754e541b9f9254fde814fcba486 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 19 May 2020 10:52:36 +0200 Subject: [PATCH 131/327] Add method-overloading exercise Add method-overloading exercise --- .../concept/method-overloading/.docs/after.md | 35 ++++++++ .../concept/method-overloading/.docs/hints.md | 24 +++++ .../method-overloading/.docs/instructions.md | 80 +++++++++++++++++ .../method-overloading/.docs/introduction.md | 25 ++++++ .../method-overloading/.meta/Example.cs | 46 ++++++++++ .../method-overloading/.meta/config.json | 8 ++ .../method-overloading/.meta/design.md | 49 +++++++++++ .../method-overloading/MethodOverloading.cs | 48 ++++++++++ .../MethodOverloading.csproj | 13 +++ .../MethodOverloadingTests.cs | 88 +++++++++++++++++++ 10 files changed, 416 insertions(+) create mode 100644 exercises/concept/method-overloading/.docs/after.md create mode 100644 exercises/concept/method-overloading/.docs/hints.md create mode 100644 exercises/concept/method-overloading/.docs/instructions.md create mode 100644 exercises/concept/method-overloading/.docs/introduction.md create mode 100644 exercises/concept/method-overloading/.meta/Example.cs create mode 100644 exercises/concept/method-overloading/.meta/config.json create mode 100644 exercises/concept/method-overloading/.meta/design.md create mode 100644 exercises/concept/method-overloading/MethodOverloading.cs create mode 100644 exercises/concept/method-overloading/MethodOverloading.csproj create mode 100644 exercises/concept/method-overloading/MethodOverloadingTests.cs diff --git a/exercises/concept/method-overloading/.docs/after.md b/exercises/concept/method-overloading/.docs/after.md new file mode 100644 index 0000000000..4dc50de6eb --- /dev/null +++ b/exercises/concept/method-overloading/.docs/after.md @@ -0,0 +1,35 @@ +[_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: + +- The number of parameters +- The type of the parameters + +There is no method overloading based on the return type. + +The compiler will automatically infer which overloaded method to call [based on the number of parameters and their type][overloading]. + +A method parameter can be made optional by assigning it a default value. When a parameter is optional, the caller is not required to supply an argument for that parameter, in which case the default value will be used. [Optional parameters][optional-arguments] _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. If a method has multiple optional parameters, you can specify only some of them using [named arguments][named-arguments]. + +```csharp +class Card +{ + static string NewYear(int year = 2020, string sender = "me") + { + return $"Happy {year} from {sender}!"; + } +} + +Card.NewYear(); // => "Happy 2020 from me!" +Card.Card(1999); // => "Happy 1999 from me!" +Card.Card(sender: "mom"); // => "Happy 2020 from mom!" +``` + +An optional parameter's value must be either: + +- A constant expression (e.g. `"hi"`, `2`, `DayOfWeek.Friday`, `null` etc.) +- A `new` expression of a value type +- A `default` expression of a value type + +[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading +[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments +[named-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments +[overloading]: https://csharpindepth.com/articles/Overloading diff --git a/exercises/concept/method-overloading/.docs/hints.md b/exercises/concept/method-overloading/.docs/hints.md new file mode 100644 index 0000000000..35e6d4290a --- /dev/null +++ b/exercises/concept/method-overloading/.docs/hints.md @@ -0,0 +1,24 @@ +### General + +- [Method overloading in C#][member-overloading]. +- [String interpolation][string-interpolation] can be used to format description strings. + +### 3. Describe the travel method + +- A [simple conditional][if-statement] can be used for the conditional logic. + +### 4. Describe a character traveling to a destination + +- You can re-use the existing describe functionality. +- You can use [expressions in interpolated strings][string-interpolation-expressions], which means you can call methods directly in the interpolated parts of an interpolated string. + +### 5. Describe a character traveling to a destination without specifying the travel method + +- You can re-use the existing functionality that does take an explicit travel method. +- You can use [optional parameters][optional-arguments] to simplify the amount of code you need. + +[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading +[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments +[string-interpolation]: https://csharp.net-tutorials.com/operators/the-string-interpolation-operator/ +[string-interpolation-expressions]: https://csharp.net-tutorials.com/operators/the-string-interpolation-operator/#aelm5419 +[if-statement]: https://csharp.net-tutorials.com/control-structures/if-statement/ diff --git a/exercises/concept/method-overloading/.docs/instructions.md b/exercises/concept/method-overloading/.docs/instructions.md new file mode 100644 index 0000000000..4a29af9d32 --- /dev/null +++ b/exercises/concept/method-overloading/.docs/instructions.md @@ -0,0 +1,80 @@ +In this exercise you're playing a role-playing game named "Wizard and Warriors" with your best friends. You are the Game Master, the person tasked with making the game world come alive for the players. A key aspect of this is describing the game to the players: what is a character's status, what the town they're visiting looks like, etc. + +You have five tasks that have you describe parts of the game to the players. + +### 1. Describe a character + +Each character has a class, level and number of hit points and is described as: `"You're a level with hit points."`. Implement the (static) `GameMaster.Describe` method that takes a `Character` as its sole parameter and returns its description. + +```csharp +var character = new Character(); +character.Class = "Wizard"; +character.Level = 4; +character.HitPoints = 28; + +GameMaster.Describe(character); +// => "You're a level 4 Wizard with 28 hit points." +``` + +### 2. Describe a destination + +Each destination has a name and a number of inhabitants and is described as: `"You've arrived at , which has inhabitants."`. Implement the (static) `GameMaster.Describe` method that takes a `Destination` as its sole parameter and returns its description. + +```csharp +var destination = new Destination(); +destination.Name = "Muros"; +destination.Inhabitants = 732; + +GameMaster.Describe(destination); +// => "You've arrived at Muros, which has 732 inhabitants." +``` + +### 3. Describe the travel method + +Characters can travel to a destination using one of two options: + +- Walking, described as: `"You're traveling to your destination by walking."` +- On horseback, described as: `"You're traveling to your destination on horseback."` + +Implement the (static) `GameMaster.Describe` method that takes a `TravelMethod` as its sole parameter and returns its description. + +```csharp +GameMaster.Describe(TravelMethod.Horseback); +// => "You're traveling to your destination on horseback." +``` + +### 4. Describe a character traveling to a destination + +When a character is traveling to a destination, this is described as a combination of the individual descriptions: `" "`. Implement the (static) `GameMaster.Describe` method that takes a `Character`, a `Destination` and a `TravelMethod` as its parameters and return its description. + +```csharp +var character = new Character(); +character.Class = "Wizard"; +character.Level = 4; +character.HitPoints = 28; + +var destination = new Destination(); +destination.Name = "Muros"; +destination.Inhabitants = 732; + +GameMaster.Describe(character, destination, TravelMethod.Horseback); +// => "You're a level 4 Wizard with 28 hit points. You're traveling to your destination on horseback. You've arrived at Muros, which has 732 inhabitants." +``` + +### 5. Describe a character traveling to a destination without specifying the travel method + +In the majority of cases, characters are traveling to a destination by walking. For convenience, players are allowed to omit mentioning their travel method, in which case walking will be assumed to be the travel method. Implement the (static) `GameMaster.Describe` method that takes a `Character` and a `Destination` as its parameters and return its description. + +```csharp +var character = new Character(); +character.Class = "Wizard"; +character.Level = 4; +character.HitPoints = 28; + +var destination = new Destination(); +destination.Name = "Muros"; +destination.Inhabitants = 732; + +GameMaster.Describe(character, destination); +// => "You're a level 4 Wizard with 28 hit points. You're traveling to your destination by walking. You've arrived at Muros, which has 732 inhabitants." +``` diff --git a/exercises/concept/method-overloading/.docs/introduction.md b/exercises/concept/method-overloading/.docs/introduction.md new file mode 100644 index 0000000000..c8ef7d9c81 --- /dev/null +++ b/exercises/concept/method-overloading/.docs/introduction.md @@ -0,0 +1,25 @@ +_Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: + +- The number of parameters +- The type of the parameters + +There is no method overloading based on the return type. + +The compiler will automatically infer which overloaded method to call based on the number of parameters and their type. + +A method parameter can be made optional by assigning it a default value. When calling a method with optional parameters, the caller is not required to pass a value for them. If no value is passed for an optional parameter, its default value will be used. + +Optional parameters _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. + +```csharp +class Card +{ + static string NewYear(int year = 2020) + { + return $"Happy {year}!"; + } +} + +Card.NewYear(); // => "Happy 2020!" +Card.Card(1999); // => "Happy 1999!" +``` diff --git a/exercises/concept/method-overloading/.meta/Example.cs b/exercises/concept/method-overloading/.meta/Example.cs new file mode 100644 index 0000000000..50fff0ecf2 --- /dev/null +++ b/exercises/concept/method-overloading/.meta/Example.cs @@ -0,0 +1,46 @@ +static class GameMaster +{ + public static string Describe(Character character) + { + return $"You're a level {character.Level} {character.Class} with {character.HitPoints} hit points."; + } + + public static string Describe(Destination destination) + { + return $"You've arrived at {destination.Name}, which has {destination.Inhabitants} inhabitants."; + } + + public static string Describe(TravelMethod travelMethod) + { + if (travelMethod == TravelMethod.Walking) + { + return "You're traveling to your destination by walking."; + } + + return "You're traveling to your destination on horseback."; + } + + public static string Describe(Character character, Destination destination, TravelMethod travelMethod = TravelMethod.Walking) + { + return $"{Describe(character)} {Describe(travelMethod)} {Describe(destination)}"; + } +} + +class Character +{ + public string Class { get; set; } + public int Level { get; set; } + public int HitPoints { get; set; } +} + +class Destination +{ + public string Name { get; set; } + public int Inhabitants { get; set; } +} + +enum TravelMethod +{ + Walking, + Horse +} diff --git a/exercises/concept/method-overloading/.meta/config.json b/exercises/concept/method-overloading/.meta/config.json new file mode 100644 index 0000000000..6d4e44d872 --- /dev/null +++ b/exercises/concept/method-overloading/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ] +} diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/method-overloading/.meta/design.md new file mode 100644 index 0000000000..e140306b08 --- /dev/null +++ b/exercises/concept/method-overloading/.meta/design.md @@ -0,0 +1,49 @@ +# Design + +## Goal + +The goal of this exercise is to teach the student the Concept of Method Overloading in C#. + +## Learning objectives + +- Know what method overloading is +- Know how to define overloaded methods +- Know the limitations of method overloading +- Know how to define optional parameters +- Know how to pass named arguments + +## Out of scope + +- Overload resolution + +## Concepts + +This Concepts Exercise's Concepts are: + +- `method-overloading`: know what method overloading is; know how to define overloaded methods; know the limitations of method overloading +- `optional-parameters`: know how to define optional parameters +- `named-arguments`: know how to use named arguments + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `classes`: know how to define methods on classes +- `constructors`: know how to define constructors on classes +- `properties`: know how to work with properties +- `enums`: know how to use enums +- `strings`: know how to format strings +- `basics`: know how to work with integers + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise could benefit from the following rules added to the the [analyzer][analyzer]: + +- Verify that the `Describe()` methods take take both a `Character` and `Destination` can be replaced with a single method that uses a default value for the `TravelMethod` parameter. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/method-overloading/MethodOverloading.cs b/exercises/concept/method-overloading/MethodOverloading.cs new file mode 100644 index 0000000000..ac7f4abf7f --- /dev/null +++ b/exercises/concept/method-overloading/MethodOverloading.cs @@ -0,0 +1,48 @@ +using System; + +static class GameMaster +{ + public static string Describe(Character character) + { + throw new NotImplementedException("Please implement the (static) GameMaster.Describe(Character) method"); + } + + public static string Describe(Destination destination) + { + throw new NotImplementedException("Please implement the (static) GameMaster.Describe(Destination) method"); + } + + public static string Describe(TravelMethod travelMethod) + { + throw new NotImplementedException("Please implement the (static) GameMaster.Describe(TravelMethod) method"); + } + + public static string Describe(Character character, Destination destination, TravelMethod travelMethod) + { + throw new NotImplementedException("Please implement the (static) GameMaster.Describe(Character, Destination, TravelMethod) method"); + } + + public static string Describe(Character character, Destination destination) + { + throw new NotImplementedException("Please implement the (static) GameMaster.Describe(Character, Destination) method"); + } +} + +class Character +{ + public string Class { get; set; } + public int Level { get; set; } + public int HitPoints { get; set; } +} + +class Destination +{ + public string Name { get; set; } + public int Inhabitants { get; set; } +} + +enum TravelMethod +{ + Walking, + Horseback +} diff --git a/exercises/concept/method-overloading/MethodOverloading.csproj b/exercises/concept/method-overloading/MethodOverloading.csproj new file mode 100644 index 0000000000..8d66e73a50 --- /dev/null +++ b/exercises/concept/method-overloading/MethodOverloading.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/method-overloading/MethodOverloadingTests.cs b/exercises/concept/method-overloading/MethodOverloadingTests.cs new file mode 100644 index 0000000000..81ec48fc48 --- /dev/null +++ b/exercises/concept/method-overloading/MethodOverloadingTests.cs @@ -0,0 +1,88 @@ +using Xunit; + +public class GameMasterTests +{ + [Fact] + public void Describe_warrior_character() + { + var character = new Character(); + character.Class = "Warrior"; + character.Level = 16; + character.HitPoints = 89; + + Assert.Equal("You're a level 16 Warrior with 89 hit points.", GameMaster.Describe(character)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_wizard_character() + { + var character = new Character(); + character.Class = "Wizard"; + character.Level = 7; + character.HitPoints = 33; + + Assert.Equal("You're a level 7 Wizard with 33 hit points.", GameMaster.Describe(character)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_small_town_destination() + { + var destination = new Destination(); + destination.Name = "Tol Honeth"; + destination.Inhabitants = 41; + + Assert.Equal("You've arrived at Tol Honeth, which has 41 inhabitants.", GameMaster.Describe(destination)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_large_town_destination() + { + var destination = new Destination(); + destination.Name = "Ashaba"; + destination.Inhabitants = 1500; + + Assert.Equal("You've arrived at Ashaba, which has 1500 inhabitants.", GameMaster.Describe(destination)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_walking_travel_method() + { + Assert.Equal("You're traveling to your destination by walking.", GameMaster.Describe(TravelMethod.Walking)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_horse_travel_method() + { + Assert.Equal("You're traveling to your destination on horseback.", GameMaster.Describe(TravelMethod.Horseback)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_character_traveling_to_destination_without_explicit_travel_method() + { + var character = new Character(); + character.Class = "Warrior"; + character.Level = 1; + character.HitPoints = 30; + + var destination = new Destination(); + destination.Name = "Vo Mimbre"; + destination.Inhabitants = 332; + + Assert.Equal("You're a level 1 Warrior with 30 hit points. You're traveling to your destination by walking. You've arrived at Vo Mimbre, which has 332 inhabitants.", GameMaster.Describe(character, destination)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Describe_character_traveling_to_destination_with_explicit_travel_method() + { + var character = new Character(); + character.Class = "Wizard"; + character.Level = 20; + character.HitPoints = 120; + + var destination = new Destination(); + destination.Name = "Camaar"; + destination.Inhabitants = 999; + + Assert.Equal("You're a level 20 Wizard with 120 hit points. You're traveling to your destination on horseback. You've arrived at Camaar, which has 999 inhabitants.", GameMaster.Describe(character, destination, TravelMethod.Horseback)); + } +} From 9137be0a352003dd458f5b9ceb7944540d5ebe0e Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 22 May 2020 16:18:34 +0200 Subject: [PATCH 132/327] Add note that test methods should have just one assertion --- reference/implementing-a-concept-exercise.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 6de2d56abb..18ccce1af6 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -62,7 +62,8 @@ For more information, please read [this in-depth description][stub-file], [watch - [xUnit][xunit] is used as the test framework. - Only use `Fact` tests; don't use `Theory` tests. - All but the first test should be skipped by default (check [this example][skip-fact]). -- Test methods should be named using `snake_case`, with the first character uppercased (check [this example][test-name]). +- Test methods must be named using `snake_case`, with the first character uppercased (check [this example][test-name]). +- Test methods must have a single assertion. For more information, please read [this in-depth description][tests-file], [watch this video][video-tests-file] and check [this example tests file][example-tests-file]. From be4f16ff4c768c31f0a3038cd9b0792d2a29cc91 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 22 May 2020 16:21:59 +0200 Subject: [PATCH 133/327] Use consistent headings in documentation --- exercises/concept/arrays/.docs/hints.md | 14 +++++++------- exercises/concept/arrays/.docs/instructions.md | 12 ++++++------ exercises/concept/basics/.docs/hints.md | 10 +++++----- exercises/concept/basics/.docs/instructions.md | 8 ++++---- exercises/concept/booleans/.docs/hints.md | 4 ++-- exercises/concept/booleans/.docs/instructions.md | 8 ++++---- exercises/concept/classes/.docs/hints.md | 14 +++++++------- exercises/concept/classes/.docs/instructions.md | 12 ++++++------ exercises/concept/constructors/.docs/hints.md | 12 ++++++------ .../concept/constructors/.docs/instructions.md | 12 ++++++------ exercises/concept/datetimes/.docs/hints.md | 12 ++++++------ exercises/concept/datetimes/.docs/instructions.md | 10 +++++----- exercises/concept/enums/.docs/hints.md | 8 ++++---- exercises/concept/enums/.docs/instructions.md | 6 +++--- exercises/concept/flag-enums/.docs/hints.md | 8 ++++---- exercises/concept/flag-enums/.docs/instructions.md | 8 ++++---- .../concept/floating-point-numbers/.docs/hints.md | 8 ++++---- .../floating-point-numbers/.docs/instructions.md | 6 +++--- exercises/concept/inheritance/.docs/hints.md | 12 ++++++------ .../concept/inheritance/.docs/instructions.md | 12 ++++++------ .../concept/method-overloading/.docs/hints.md | 8 ++++---- .../method-overloading/.docs/instructions.md | 10 +++++----- exercises/concept/nullability/.docs/hints.md | 6 +++--- .../concept/nullability/.docs/instructions.md | 6 +++--- exercises/concept/numbers/.docs/hints.md | 6 +++--- exercises/concept/numbers/.docs/instructions.md | 4 ++-- exercises/concept/properties/.docs/hints.md | 12 ++++++------ exercises/concept/properties/.docs/instructions.md | 10 +++++----- exercises/concept/properties/.docs/introduction.md | 4 ++-- exercises/concept/strings/.docs/hints.md | 8 ++++---- exercises/concept/strings/.docs/instructions.md | 6 +++--- 31 files changed, 138 insertions(+), 138 deletions(-) diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/arrays/.docs/hints.md index 4deaab12e2..0bd9f555f9 100644 --- a/exercises/concept/arrays/.docs/hints.md +++ b/exercises/concept/arrays/.docs/hints.md @@ -1,33 +1,33 @@ -### General +## General - The bird count per day is stored in a [field][fields] named `birdsPerDay`. - The bird count per day is an array that contains exactly 7 integers. -### 1. Check what the counts were last week +## 1. Check what the counts were last week - As this method does _not_ depend on the current week's count, it is defined as a [`static` method][static-members]. - There are [several ways to define an array][single-dimensional-arrays]. -### 2. Check how many birds visited today +## 2. Check how many birds visited today - Remember that the counts are ordered by day from oldest to most recent, with the last element representing today. - Accessing the last element can be done either by using its (fixed) index (remember to start counting from zero) or by calculating its index using the [array's size][array-length]. -### 3. Increment today's count +## 3. Increment today's count - Set the element representing today's count to today's count plus 1. -### 4. Check if there was a day with no visiting birds +## 4. Check if there was a day with no visiting birds - The `Array` class has a [built-in method][array-indexof] that returns the first index where the element is found, or -1 if no matching element was found. -### 5. Calculate the total number of visiting birds +## 5. Calculate the total number of visiting birds - A variable can be used to hold the total number of visiting birds. - The array can be iterated over using a [`foreach` loop][array-foreach]. - The variable can be updated inside the loop. -### 6. Calculate the number of busy days +## 6. Calculate the number of busy days - A variable can be used to hold the number of busy days. - The array can be iterated over using a [`foreach` loop][array-foreach]. diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md index f9d41d42b6..3e3ee40817 100644 --- a/exercises/concept/arrays/.docs/instructions.md +++ b/exercises/concept/arrays/.docs/instructions.md @@ -2,7 +2,7 @@ You're an avid bird watcher that keeps track of how many birds have visited your You have six tasks, all dealing with the numbers of birds that visited your garden. -### 1. Check what the counts were last week +## 1. Check what the counts were last week For comparison purposes, you always keep a copy of last week's counts nearby, which were: 0, 2, 5, 3, 7, 8 and 4. Implement the (_static_) `BirdCount.LastWeek()` method that returns last week's counts: @@ -11,7 +11,7 @@ BirdCount.LastWeek(); // => [0, 2, 5, 3, 7, 8, 4] ``` -### 2. Check how many birds visited today +## 2. Check how many birds visited today Implement the `BirdCount.Today()` method to return how many birds visited your garden today. The bird counts are ordered by day, with the first element being the count of the oldest day, and the last element being today's count. @@ -22,7 +22,7 @@ birdCount.Today(); // => 1 ``` -### 3. Increment today's count +## 3. Increment today's count Implement the `BirdCount.IncrementDayCount()` method to increment today's count: @@ -34,7 +34,7 @@ birdCount.Today(); // => 2 ``` -### 4. Check if there was a day with no visiting birds +## 4. Check if there was a day with no visiting birds Implement the `BirdCount.HasDayWithoutBirds()` method that returns `true` if there was a day at which zero birds visited the garden; otherwise, return `false`: @@ -45,7 +45,7 @@ birdCount.HasDayWithoutBirds(); // => true ``` -### 5. Calculate the total number of visiting birds +## 5. Calculate the total number of visiting birds Implement the `BirdCount.Total()` method to return the total number of birds that have visited your garden: @@ -56,7 +56,7 @@ birdCount.Total(); // => 19 ``` -### 6. Calculate the number of busy days +## 6. Calculate the number of busy days Some days are busier that others. A busy day is one where five or more birds have visited your garden. Implement the `BirdCount.BusyDays()` method to return the number of busy days: diff --git a/exercises/concept/basics/.docs/hints.md b/exercises/concept/basics/.docs/hints.md index c8506ba7c8..5607ce2aed 100644 --- a/exercises/concept/basics/.docs/hints.md +++ b/exercises/concept/basics/.docs/hints.md @@ -1,27 +1,27 @@ -### General +## General - An [integer value][integers] can be defined as one or more consecutive digits. -### 1. Define the expected oven time in minutes +## 1. Define the expected oven time in minutes - You need to define a [method][methods] without any arguments. - You need to return an [integer][integers]. -### 2. Calculate the remaining oven time in minutes +## 2. Calculate the remaining oven time in minutes - You need to define a [method][methods] with a single parameter. - You have to [explicitly return an integer][return] from a method. - The method's parameter is an [integer][integers]. - You can use the [mathematical operator for subtraction][operators] to subtract values. -### 3. Calculate the preparation time in minutes +## 3. Calculate the preparation time in minutes - You need to define a [method][methods] with a single parameter. - You have to [explicitly return an integer][return] from a method. - The method's parameter is an [integer][integers]. - You can use the [mathematical operator for multiplicaton][operators] to multiply values. -### 4. Calculate the total working time in minutes +## 4. Calculate the total working time in minutes - You need to define a [method][methods] with two parameters. - You have to [explicitly return an integer][return] from a method. diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/basics/.docs/instructions.md index fd10cc0d57..baeaa1eccd 100644 --- a/exercises/concept/basics/.docs/instructions.md +++ b/exercises/concept/basics/.docs/instructions.md @@ -2,7 +2,7 @@ In this exercise you're going to write some code to help you cook a brilliant la You have four tasks, all related to the time spent cooking the lasasgna. -### 1. Define the expected oven time in minutes +## 1. Define the expected oven time in minutes Define the `Lasagna.ExpectedMinutesInOven()` method that does not take any parameters and returns how many minutes the lasagna should be in the oven. According to the cooking book, the expected oven time in minutes is 40: @@ -12,7 +12,7 @@ lasagna.ExpectedMinutesInOven(); // => 40 ``` -### 2. Calculate the remaining oven time in minutes +## 2. Calculate the remaining oven time in minutes Define the `Lasagna.RemainingMinutesInOven()` method that takes the actual minutes the lasagna has been in the oven as a parameter and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task. @@ -22,7 +22,7 @@ lasagna.RemainingMinutesInOven(30); // => 10 ``` -### 3. Calculate the preparation time in minutes +## 3. Calculate the preparation time in minutes Define the `Lasagna.PreparationTimeInMinutes()` method that takes the number of layers you added to the lasagna as a parameter and returns how many minutes you spent preparing the lasagna, assuming each layer takes you 2 minutes to prepare. @@ -32,7 +32,7 @@ lasagna.PreparationTimeInMinutes(2); // => 4 ``` -### 4. Calculate the total working time in minutes +## 4. Calculate the total working time in minutes Define the `Lasagna.TotalTimeInMinutes()` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. diff --git a/exercises/concept/booleans/.docs/hints.md b/exercises/concept/booleans/.docs/hints.md index 178a5af90d..9e631dd402 100644 --- a/exercises/concept/booleans/.docs/hints.md +++ b/exercises/concept/booleans/.docs/hints.md @@ -1,9 +1,9 @@ -### General +## General - There are three [boolean operators][operators] to work with boolean values. - Multiple operators can be combined in a single expression. -### 1. Check if a fast attack can be made +## 1. Check if a fast attack can be made - The [boolean operators][operators] can also be applied to boolean parameters. diff --git a/exercises/concept/booleans/.docs/instructions.md b/exercises/concept/booleans/.docs/instructions.md index f22f4570f8..2f02278acb 100644 --- a/exercises/concept/booleans/.docs/instructions.md +++ b/exercises/concept/booleans/.docs/instructions.md @@ -13,7 +13,7 @@ You have four tasks: to implement the logic for determining if the above actions ## Tasks -### 1. Check if a fast attack can be made +## 1. Check if a fast attack can be made Implement the (_static_) `QuestLogic.CanFastAttack()` method that takes a boolean value that indicates if the knight is awake. This method returns `true` if a fast attack can be made based on the state of the knight. Otherwise, returns `false`: @@ -23,7 +23,7 @@ QuestLogic.CanFastAttack(knightIsAwake); // => false ``` -### 2. Check if the group can be spied upon +## 2. Check if the group can be spied upon Implement the (_static_) `QuestLogic.CanSpy()` method that takes three boolean values, indicating if the knight, archer and the prisoner, respectively, are awake. The method returns `true` if the group can be spied upon, based on the state of the three characters. Otherwise, returns `false`: @@ -35,7 +35,7 @@ QuestLogic.CanSpy(knightIsAwake, archerIsAwake, prisonerIsAwake); // => true ``` -### 3. Check if the prisoner can be signalled +## 3. Check if the prisoner can be signalled Implement the (_static_) `QuestLogic.CanSignalPrisoner()` method that takes two boolean values, indicating if the archer and the prisoner, respectively, are awake. The method returns `true` if the prisoner can be signalled, based on the state of the two characters. Otherwise, returns `false`: @@ -46,7 +46,7 @@ QuestLogic.CanSignalPrisoner(archerIsAwake, prisonerIsAwake); // => true ``` -### 4. Check if the prisoner can be freed +## 4. Check if the prisoner can be freed Implement the (_static_) `QuestLogic.CanFreePrisoner()` method that takes four boolean values. The first three parameters indicate if the knight, archer and the prisoner, respectively, are awake. The last parameter indicates if Annalyn's pet dog is present. The method returns `true` if the prisoner can be freed based on the state of the three characters and Annalyn's pet dog presence. Otherwise, it returns `false`: diff --git a/exercises/concept/classes/.docs/hints.md b/exercises/concept/classes/.docs/hints.md index ba4002abad..a63d6f70d0 100644 --- a/exercises/concept/classes/.docs/hints.md +++ b/exercises/concept/classes/.docs/hints.md @@ -1,31 +1,31 @@ -### General +## General -### 1. Buy a brand-new remote controlled car +## 1. Buy a brand-new remote controlled car - [This page shows how to create a new instance of a class][creating-objects]. -### 2. Display the distance driven +## 2. Display the distance driven - Keep track of the distance driven in a [field][fields]. - Consider what visibility to use for the field (does it need to be used outside the class?). - Consider using [string interpolation][string-interpolation] to format the string to return. -### 3. Display the battery percentage +## 3. Display the battery percentage - Keep track of the distance driven in a [field][fields]. - Initialize the field to a specific value to correspond to the initial battery charge. - Consider what visibility to use for the field (does it need to be used outside the class?). - Consider using [string interpolation][string-interpolation] to format the string to return. -### 4. Update the number of meters driven when driving +## 4. Update the number of meters driven when driving - Update the field representing the distance driven. -### 5. Update the battery percentage when driving +## 5. Update the battery percentage when driving - Update the field representing the battery percentage driven. -### 6. Prevent driving when the battery is drained +## 6. Prevent driving when the battery is drained - Add a conditional to only update the distance and battery if the battery is not already drained. - Add a conditional to display the empty battery message if the battery is drained. diff --git a/exercises/concept/classes/.docs/instructions.md b/exercises/concept/classes/.docs/instructions.md index 19f281834b..1d57a5ba6b 100644 --- a/exercises/concept/classes/.docs/instructions.md +++ b/exercises/concept/classes/.docs/instructions.md @@ -11,7 +11,7 @@ If the battery is at 0%, you can't drive the car anymore and the battery display You have six tasks, each of which will work with remote controlled car instances. -### 1. Buy a brand-new remote controlled car +## 1. Buy a brand-new remote controlled car Implement the (_static_) `RemoteControlCar.Buy()` method to return a brand-new remote controlled car instance: @@ -19,7 +19,7 @@ Implement the (_static_) `RemoteControlCar.Buy()` method to return a brand-new r RemoteControlCar car = RemoteControlCar.Buy(); ``` -### 2. Display the distance driven +## 2. Display the distance driven Implement the `RemoteControlCar.DistanceDisplay()` method to return the distance as displayed on the LED display: @@ -29,7 +29,7 @@ car.DistanceDisplay(); // => "Driven 0 meters" ``` -### 3. Display the battery percentage +## 3. Display the battery percentage Implement the `RemoteControlCar.BatteryDisplay()` method to return the distance as displayed on the LED display: @@ -39,7 +39,7 @@ car.BatteryDisplay(); // => "Battery at 100%" ``` -### 4. Update the number of meters driven when driving +## 4. Update the number of meters driven when driving Implement the `RemoteControlCar.Drive()` method that updates the number of meters driven: @@ -51,7 +51,7 @@ car.DistanceDisplay(); // => "Driven 40 meters" ``` -### 5. Update the battery percentage when driving +## 5. Update the battery percentage when driving Update the `RemoteControlCar.Drive()` method to update the battery percentage: @@ -63,7 +63,7 @@ car.BatteryDisplay(); // => "Battery at 98%" ``` -### 6. Prevent driving when the battery is drained +## 6. Prevent driving when the battery is drained Update the `RemoteControlCar.Drive()` method to not increase the distance driven nor decrease the battery percentage when the battery is drained (at 0%): diff --git a/exercises/concept/constructors/.docs/hints.md b/exercises/concept/constructors/.docs/hints.md index 2eb06954fd..1c32c838f1 100644 --- a/exercises/concept/constructors/.docs/hints.md +++ b/exercises/concept/constructors/.docs/hints.md @@ -1,30 +1,30 @@ -### 1. Creating a remote controlled car +## 1. Creating a remote controlled car - [Define a constructor][constructor-syntax] that has two `int` parameters. - Store the two parameters as [fields][fields] to access them from the classes' methods. -### 2. Creating a race track +## 2. Creating a race track - [Define a constructor][constructor-syntax] that has one `int` parameter. - Store the parameter as a [field][fields] to access it from the class' method. -### 3. Drive the car +## 3. Drive the car - Add a [field][fields] to keep track of the distance driven. - Add the car's speed to the [field][fields] that keeps track of the distance driven. -### 4. Check for a drained battery +## 4. Check for a drained battery - Add a [field][fields] to keep track of the remaining battery charge percentage (starts at 100%). - Remove the car's battery drain from the [field][fields] to keep track of the battery charge. - Don't update the distance driven if the battery is drained. - Remember that if the battery charge is less than the battery drain percentage, it is considered drained. -### 5. Create the Nitro remote control car +## 5. Create the Nitro remote control car - [Instantiate][instance-constructors] an instance of the `RemoteControlCar` with the correct arguments. -### 6. Check if a remote control car can finish a race +## 6. Check if a remote control car can finish a race - Solving this is probably best done by [repeatedly driving the car][while]. - Remember that the car has a method to retrieve the distance it has driven. diff --git a/exercises/concept/constructors/.docs/instructions.md b/exercises/concept/constructors/.docs/instructions.md index 25de2d29fe..6c495a5750 100644 --- a/exercises/concept/constructors/.docs/instructions.md +++ b/exercises/concept/constructors/.docs/instructions.md @@ -8,7 +8,7 @@ Each race track has its own distance. Cars are tested by checking if they can fi You have six tasks, each of which will work with remote controller car instances. -### 1. Creating a remote controlled car +## 1. Creating a remote controlled car Allow creating a remote controller car by defining a constructor for the `RemoteControlCar` class that takes the speed of the car in meters and the battery drain percentage as its two parameters (both of type `int`): @@ -18,7 +18,7 @@ int batteryDrain = 2; var car = new RemoteControlCar(speed, batteryDrain); ``` -### 2. Creating a race track +## 2. Creating a race track Allow creating a race track by defining a constructor for the `RaceTrack` class that takes the track's distance in meters as its sole parameter (which is of type `int`): @@ -27,7 +27,7 @@ int distance = 800; var raceTrack = new RaceTrack(distance); ``` -### 3. Drive the car +## 3. Drive the car Implement the `RemoteControlCar.Drive()` method that updates the number of meters driven based on the car's speed. Also implement the `RemoteControlCar.DistanceDriven()` method to return the number of meters driven by the car: @@ -41,7 +41,7 @@ car.DistanceDriven(); // => 5 ``` -### 4. Check for a drained battery +## 4. Check for a drained battery Update the `RemoteControlCar.Drive()` method to drain the battery based on the car's battery drain. Also implement the `RemoteControlCar.BatteryDrained()` method that indicates if the battery is drained: @@ -55,7 +55,7 @@ car.BatteryDrained(); // => false ``` -### 5. Create the Nitro remote control car +## 5. Create the Nitro remote control car The best-selling remote control car is the Nitro, which has a stunning top speed of 50 meters with a battery drain of 4%. Implement the (static) `RemoteControlCar.Nitro()` method to return this type of car: @@ -65,7 +65,7 @@ car.Drive(); car.DistanceDriven(); // => 50 -### 6. Check if a remote control car can finish a race +## 6. Check if a remote control car can finish a race To finish a race, a car has to be able to drive the race's distance. This means not draining its battery before having crossed the finish line. Implement the `Race.CarCanFinish()` method that takes a `RemoteControlCar` instance as its parameter and returns `true` if the car can finish the race; otherwise, return `false`: diff --git a/exercises/concept/datetimes/.docs/hints.md b/exercises/concept/datetimes/.docs/hints.md index 808ee7fcbd..4209ebd50c 100644 --- a/exercises/concept/datetimes/.docs/hints.md +++ b/exercises/concept/datetimes/.docs/hints.md @@ -1,26 +1,26 @@ -### General +## General - [Tutorial on dates and time by csharp.net][csharp.net-datetimes-working-with-datetimes-time] -### 1. Parse appointment date +## 1. Parse appointment date - The `DateTime` class has several methods to [parse][docs.microsoft.com_parsing-date] a `string` to a `DateTime`. -### 2. Check if an appointment has already passed +## 2. Check if an appointment has already passed - `DateTime` objects can be compared using the default [comparison operators][docs.microsoft.com_datetime-operators]. - There is a [property][docs.microsoft.com_datetime-properties] to retrieve the current date and time. -### 3. Check if appointment is in the afternoon +## 3. Check if appointment is in the afternoon - Accessing the time portion of a `DateTime` object can de done through one of its [properties][docs.microsoft.com_datetime-properties]. -### 4. Describe the time and date of the appointment +## 4. Describe the time and date of the appointment - The tests are running as if running on a machine in the United States, which means that when converting a `DateTime` to a `string` will return dates and time in US format. - When converting a `DateTime` instance to a `string`, you can use either a [standard format string][docs.microsoft.com_standard-date-and-time-format-strings] or a [custom format string][docs.microsoft.com_custom-date-and-time-format-strings]. -### 5. Return the anniversary date +## 5. Return the anniversary date - Use one of the various `DateTime` [constructors][constructors] to create a new `DateTime` instance. - You can use one of the current date time's [properties][docs.microsoft.com_datetime-properties] to get the current year. diff --git a/exercises/concept/datetimes/.docs/instructions.md b/exercises/concept/datetimes/.docs/instructions.md index 8fb319d19b..bfa03caf42 100644 --- a/exercises/concept/datetimes/.docs/instructions.md +++ b/exercises/concept/datetimes/.docs/instructions.md @@ -9,7 +9,7 @@ You have four tasks, which will all involve appointment dates. The dates and tim The tests will automatically set the culture to `en-US` - you don't have to set or specify the culture yourselves. -### 1. Parse appointment date +## 1. Parse appointment date Implement the (_static_) `Appointment.Schedule()` method to parse a textual representation of an appointment date into the corresponding `DateTime` format: @@ -18,7 +18,7 @@ Appointment.Schedule("7/25/2019 13:45:00") // => new DateTime(2019, 7, 25, 13, 45, 0) ``` -### 2. Check if an appointment has already passed +## 2. Check if an appointment has already passed Implement the (_static_) `Appointment.HasPassed()` method that takes an appointment date and checks if the appointment was somewhere in the past: @@ -27,7 +27,7 @@ Appointment.HasPassed(new DateTime(1999, 12, 31, 9, 0, 0)) // => true ``` -### 3. Check if appointment is in the afternoon +## 3. Check if appointment is in the afternoon Implement the (_static_) `Appointment.IsAfternoonAppointment()` method that takes an appointment date and checks if the appointment is in the afternoon (>= 12:00 and < 18:00): @@ -36,7 +36,7 @@ Appointment.IsAfternoonAppointment(new DateTime(2019, 03, 29, 15, 0, 0)) // => true ``` -### 4. Describe the time and date of the appointment +## 4. Describe the time and date of the appointment Implement the (_static_) `Appointment.Description()` method that takes an appointment date and returns a description of that date and time: @@ -45,7 +45,7 @@ Appointment.Description(new DateTime(2019, 03, 29, 15, 0, 0)) // => "You have an appointment on Friday 29 March 2019 at 15:00." ``` -### 5. Return the anniversary date +## 5. Return the anniversary date Implement the (_static_) `Appointment.AnniversaryDate()` method that returns this year's anniversary date, which is September 15th: diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/enums/.docs/hints.md index e76126fcea..0af01c46ec 100644 --- a/exercises/concept/enums/.docs/hints.md +++ b/exercises/concept/enums/.docs/hints.md @@ -1,17 +1,17 @@ -### General +## General - [Tutorial on working with enums][docs.microsoft.com-enumeration-types]. -### 1. Parse log level +## 1. Parse log level - There is a [method to get a part of a string](https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=netcore-3.1). - You can use a [`switch` statement](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch) to elegantly handle the various log levels. -### 2. Support unknown log level +## 2. Support unknown log level - There is a [special switch case](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case) that can be used to catch unspecified cases. -### 3. Convert log line to short format +## 3. Convert log line to short format - One can [assign specific values to enum members][docs.microsoft.com_creating-an-enumeration-type]. - Converting an enum to a number can be done through [casting][docs.microsoft.com_enumeration-types-casting] or by using a [format string][docs.microsoft.com_system.enum.tostring]. diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/enums/.docs/instructions.md index ff0b887eca..9e26f8508e 100644 --- a/exercises/concept/enums/.docs/instructions.md +++ b/exercises/concept/enums/.docs/instructions.md @@ -13,7 +13,7 @@ These are the different log levels: You have three tasks. -### 1. Parse log level +## 1. Parse log level Define a `LogLevel` enum that has six elements corresponding to the above log levels. @@ -31,7 +31,7 @@ LogLine.ParseLogLevel("[INF]: File deleted") // => LogLevel.Info ``` -### 2. Support unknown log level +## 2. Support unknown log level Unfortunately, occasionally some log lines have an unknown log level. To gracefully handle these log lines, add an `Unknown` element to the `LogLevel` enum which should be returned when parsing an unknown log level: @@ -40,7 +40,7 @@ LogLine.ParseLogLevel("[XYZ]: Overly specific, out of context message") // => LogLevel.Unknown ``` -### 3. Convert log line to short format +## 3. Convert log line to short format The log level of a log line is quite verbose. To reduce the disk space needed to store the log lines, a short format is developed: `"[]:"`. diff --git a/exercises/concept/flag-enums/.docs/hints.md b/exercises/concept/flag-enums/.docs/hints.md index 64597fe918..3f57c30815 100644 --- a/exercises/concept/flag-enums/.docs/hints.md +++ b/exercises/concept/flag-enums/.docs/hints.md @@ -1,17 +1,17 @@ -### 1. Get default permissions for an account type +## 1. Get default permissions for an account type - To handle each account type, one could use an `if` statement, but the [`switch` statement][docs.microsoft.com-switch-keyword] is a great alternative. - Combining flags means setting a specific bit to `1` using one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. -### 2. Grant a permission +## 2. Grant a permission - Combining flags means setting a specific bit to `1` using one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. -### 3. Revoke a permission +## 3. Revoke a permission - Removing a flag means setting a specific bit to `0` using a combination of two [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. -### 4. Check for a permission +## 4. Check for a permission - Checking a permission can be done by checking the result of applying one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators]. diff --git a/exercises/concept/flag-enums/.docs/instructions.md b/exercises/concept/flag-enums/.docs/instructions.md index c42b862b34..8dea940d13 100644 --- a/exercises/concept/flag-enums/.docs/instructions.md +++ b/exercises/concept/flag-enums/.docs/instructions.md @@ -14,7 +14,7 @@ Sometimes individual permissions are modified, for example giving a guest accoun You have four tasks. -### 1. Get default permissions for an account type +## 1. Get default permissions for an account type First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions. @@ -25,7 +25,7 @@ Permissions.Default(AccountType.Guest) // => Permission.Read ``` -### 2. Grant a permission +## 2. Grant a permission Implement the (_static_) `Permissions.Grant()` method that grants (adds) a permission: @@ -34,7 +34,7 @@ Permissions.Grant(current: Permission.None, grant: Permission.Read) // => Permission.Read ``` -### 3. Revoke a permission +## 3. Revoke a permission Implement the (_static_) `Permissions.Revoke()` method that revokes (removes) a permission: @@ -43,7 +43,7 @@ Permissions.Revoke(current: Permission.Read, grant: Permission.Read) // => Permission.None ``` -### 4. Check for a permission +## 4. Check for a permission Implement the (_static_) `Permissions.Check()` method that takes the current account's permissions and checks if the account is authorized for a given permission: diff --git a/exercises/concept/floating-point-numbers/.docs/hints.md b/exercises/concept/floating-point-numbers/.docs/hints.md index e4909a899e..fa59d9f52b 100644 --- a/exercises/concept/floating-point-numbers/.docs/hints.md +++ b/exercises/concept/floating-point-numbers/.docs/hints.md @@ -1,16 +1,16 @@ -### General +## General - [Floating-point numeric types introduction][docs.microsoft.com-floating_point_numeric_types]. -### 1. Calculate the interest rate +## 1. Calculate the interest rate - By default, any floating-point number defined in C# code is treated as a `double`. To use a different floating-point type (like `float` or `decimal`), one must add the appropriate [suffix][docs.microsoft.com-real_literals] to the number. -### 2. Calculate the annual balance update +## 2. Calculate the annual balance update - When calculating the annual yield, it might be useful to temporarily convert a negative balance to a positive one. One could use arithmetic here, or one of the methods in the [`Math` class][docs-microsoft.com-system.math]. -### 3. Calculate the years before reaching the desired balance +## 3. Calculate the years before reaching the desired balance - To calculate the years, one can keep looping until the desired balance is reached. C# has several [looping constructs][docs.microsoft.com-loops]. - There is a special [operator][increment-operator] to increment values by 1. diff --git a/exercises/concept/floating-point-numbers/.docs/instructions.md b/exercises/concept/floating-point-numbers/.docs/instructions.md index c68bac30ea..0f32d3ef04 100644 --- a/exercises/concept/floating-point-numbers/.docs/instructions.md +++ b/exercises/concept/floating-point-numbers/.docs/instructions.md @@ -7,7 +7,7 @@ In this exercise you'll be working with savings accounts. Each year, the balance You have three tasks, each of which will deal your balance and its interest rate. -### 1. Calculate the interest rate +## 1. Calculate the interest rate Implement the (_static_) `SavingsAccount.InterestRate()` method to calculate the interest rate based on the specified balance: @@ -18,7 +18,7 @@ SavingsAccount.InterestRate(balance: 200.75m) Note that the value returned is a `float`. -### 2. Calculate the annual balance update +## 2. Calculate the annual balance update Implement the (_static_) `SavingsAccount.AnnualBalanceUpdate()` method to calculate the annual balance update, taking into account the interest rate: @@ -29,7 +29,7 @@ SavingsAccount.AnnualBalanceUpdate(balance: 200.75m) Note that the value returned is a `decimal`. -### 3. Calculate the years before reaching the desired balance +## 3. Calculate the years before reaching the desired balance Implement the (_static_) `SavingsAccount.YearsBeforeDesiredBalance()` method to calculate the minimum number of years required to reach the desired balance: diff --git a/exercises/concept/inheritance/.docs/hints.md b/exercises/concept/inheritance/.docs/hints.md index 70dcec008f..01dda0bea1 100644 --- a/exercises/concept/inheritance/.docs/hints.md +++ b/exercises/concept/inheritance/.docs/hints.md @@ -1,27 +1,27 @@ -### 1. Describe a character +## 1. Describe a character - Modify the [constructors][constructor-syntax] of the `Wizard` and `Warrior` classes to pass their character type to the [base class' constructor][instance-constructors]. - Store the character type as a [field][fields] on the `Character` class. - The `Character` class implicitly inherits from the `object` class, which [`ToString()` method you can override][override-tostring]. -### 2. Make characters not vulnerable by default +## 2. Make characters not vulnerable by default - Implement the `Vulnerable()` method in the `Character` class to always return `false`. -### 3. Allow Wizards to prepare a spell +## 3. Allow Wizards to prepare a spell - Add a field to the `Wizard` class to store if a spell was prepared and update this in the `PrepareSpell()` method. - The spell should start out as not being prepared. -### 4. Make Wizards vulnerable when not having prepared a spell +## 4. Make Wizards vulnerable when not having prepared a spell - Override the `Vulnerable()` method in the `Wizard` class to make Wizards vulnerable if they haven't prepared a spell. -### 5. Calculate the damage points for a Wizard +## 5. Calculate the damage points for a Wizard - Use a [conditional statement][if-else] to return the the damage points, taking into account the value of the prepare spell field. -### 6. Calculate the damage points for a Warrior +## 6. Calculate the damage points for a Warrior - You can call a method on the passed `Character` instance to determine its vulnerability. - Use a [conditional statement][if-else] to return the the damage points, taking into account the vulnerability of the target. diff --git a/exercises/concept/inheritance/.docs/instructions.md b/exercises/concept/inheritance/.docs/instructions.md index 11a1f234a8..cf4321f055 100644 --- a/exercises/concept/inheritance/.docs/instructions.md +++ b/exercises/concept/inheritance/.docs/instructions.md @@ -16,7 +16,7 @@ In general, characters are never vulnerable. However, Wizards _are_ vulnerable i You have six tasks that work with Warriors and Wizard characters. -### 1. Describe a character +## 1. Describe a character Override the `ToString()` method on the `Character` class to return a description of the character, formatted as `"Character is a "`. @@ -26,7 +26,7 @@ warrior.ToString(); // => "Character is a Warrior" ``` -### 2. Make characters not vulnerable by default +## 2. Make characters not vulnerable by default Ensure that the `Character.Vulnerable()` method always returns `false`. @@ -36,7 +36,7 @@ warrior.Vulnerable(); // => false ``` -### 3. Allow Wizards to prepare a spell +## 3. Allow Wizards to prepare a spell Implement the `Wizard.PrepareSpell()` method to allow a Wizard to prepare a spell in advance. @@ -45,7 +45,7 @@ var wizard = new Wizard(); wizard.PrepareSpell(); ``` -### 4. Make Wizards vulnerable when not having prepared a spell +## 4. Make Wizards vulnerable when not having prepared a spell Ensure that the `Vulnerable()` method returns `true` if the wizard did not prepare a spell; otherwise, return `false`. @@ -55,7 +55,7 @@ wizard.Vulnerable(); // => true ``` -### 5. Calculate the damage points for a Wizard +## 5. Calculate the damage points for a Wizard Implement the `Wizard.DamagePoints()` method to return the damage points dealt: 12 damage points when a spell has been prepared, 3 damage points when not. @@ -68,7 +68,7 @@ wizard.DamagePoints(warrior); // => 12 ``` -### 6. Calculate the damage points for a Warrior +## 6. Calculate the damage points for a Warrior Implement the `Warrior.DamagePoints()` method to return the damage points dealt: 10 damage points when the target is vulnerable, 6 damage points when not. diff --git a/exercises/concept/method-overloading/.docs/hints.md b/exercises/concept/method-overloading/.docs/hints.md index 35e6d4290a..81e1b8e59f 100644 --- a/exercises/concept/method-overloading/.docs/hints.md +++ b/exercises/concept/method-overloading/.docs/hints.md @@ -1,18 +1,18 @@ -### General +## General - [Method overloading in C#][member-overloading]. - [String interpolation][string-interpolation] can be used to format description strings. -### 3. Describe the travel method +## 3. Describe the travel method - A [simple conditional][if-statement] can be used for the conditional logic. -### 4. Describe a character traveling to a destination +## 4. Describe a character traveling to a destination - You can re-use the existing describe functionality. - You can use [expressions in interpolated strings][string-interpolation-expressions], which means you can call methods directly in the interpolated parts of an interpolated string. -### 5. Describe a character traveling to a destination without specifying the travel method +## 5. Describe a character traveling to a destination without specifying the travel method - You can re-use the existing functionality that does take an explicit travel method. - You can use [optional parameters][optional-arguments] to simplify the amount of code you need. diff --git a/exercises/concept/method-overloading/.docs/instructions.md b/exercises/concept/method-overloading/.docs/instructions.md index 4a29af9d32..d69f819c1d 100644 --- a/exercises/concept/method-overloading/.docs/instructions.md +++ b/exercises/concept/method-overloading/.docs/instructions.md @@ -2,7 +2,7 @@ In this exercise you're playing a role-playing game named "Wizard and Warriors" You have five tasks that have you describe parts of the game to the players. -### 1. Describe a character +## 1. Describe a character Each character has a class, level and number of hit points and is described as: `"You're a level with hit points."`. Implement the (static) `GameMaster.Describe` method that takes a `Character` as its sole parameter and returns its description. @@ -16,7 +16,7 @@ GameMaster.Describe(character); // => "You're a level 4 Wizard with 28 hit points." ``` -### 2. Describe a destination +## 2. Describe a destination Each destination has a name and a number of inhabitants and is described as: `"You've arrived at , which has inhabitants."`. Implement the (static) `GameMaster.Describe` method that takes a `Destination` as its sole parameter and returns its description. @@ -29,7 +29,7 @@ GameMaster.Describe(destination); // => "You've arrived at Muros, which has 732 inhabitants." ``` -### 3. Describe the travel method +## 3. Describe the travel method Characters can travel to a destination using one of two options: @@ -43,7 +43,7 @@ GameMaster.Describe(TravelMethod.Horseback); // => "You're traveling to your destination on horseback." ``` -### 4. Describe a character traveling to a destination +## 4. Describe a character traveling to a destination When a character is traveling to a destination, this is described as a combination of the individual descriptions: `" "`. Implement the (static) `GameMaster.Describe` method that takes a `Character`, a `Destination` and a `TravelMethod` as its parameters and return its description. @@ -61,7 +61,7 @@ GameMaster.Describe(character, destination, TravelMethod.Horseback); // => "You're a level 4 Wizard with 28 hit points. You're traveling to your destination on horseback. You've arrived at Muros, which has 732 inhabitants." ``` -### 5. Describe a character traveling to a destination without specifying the travel method +## 5. Describe a character traveling to a destination without specifying the travel method In the majority of cases, characters are traveling to a destination by walking. For convenience, players are allowed to omit mentioning their travel method, in which case walking will be assumed to be the travel method. Implement the (static) `GameMaster.Describe` method that takes a `Character` and a `Destination` as its parameters and return its description. diff --git a/exercises/concept/nullability/.docs/hints.md b/exercises/concept/nullability/.docs/hints.md index 5a79189026..dc29d8bdc6 100644 --- a/exercises/concept/nullability/.docs/hints.md +++ b/exercises/concept/nullability/.docs/hints.md @@ -1,14 +1,14 @@ -### 1. Print a badge for an employee +## 1. Print a badge for an employee - [String interpolation][string-interpolation] can be used to concisely format the badge. - There is a [built-in method to convert a string to uppercase][toupper]. -### 2. Print a badge for a new employee +## 2. Print a badge for a new employee - You should check if the ID is `null` before using it. - [This tutorial goes into detail how to work with nullable value types][nullable-types-tutorial]. -### 3. Print a badge for the owner +## 3. Print a badge for the owner - You should check if the department is `null` before using it. - [This tutorial goes into detail how to work with nullable reference types][nullable-reference-types-tutorial]. diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/nullability/.docs/instructions.md index e609dcea50..3c383a9e2c 100644 --- a/exercises/concept/nullability/.docs/instructions.md +++ b/exercises/concept/nullability/.docs/instructions.md @@ -1,6 +1,6 @@ In this exercise you'll be writing code to print name badges for factory employees. -### 1. Print a badge for an employee +## 1. Print a badge for an employee Employees have an ID, name and department name. Employee badge labels are formatted as follows: `"[id] - [name] - [DEPARTMENT]"`. Implement the (_static_) `Badge.Print()` method to return an employee's badge label: @@ -11,7 +11,7 @@ Badge.Print(734, "Ernest Johnny Payne", "Strategic Communication"); Note that the department should be uppercased on the label. -### 2. Print a badge for a new employee +## 2. Print a badge for a new employee Due to a quirk in the computer system, new employees occasionally don't yet have an ID when they start working at the factory. As badges are required, they will receive a temporary badge without the ID prefix. Modify the (_static_) `Badge.Print()` method to support new employees that don't yet have an ID: @@ -20,7 +20,7 @@ Badge.Print(id: null, "Jane Johnson", "Procurement"); // => "Jane Johnson - PROCUREMENT" ``` -### 3. Print a badge for the owner +## 3. Print a badge for the owner Even the factory's owner has to wear a badge at all times. However, an owner does not have a department. In this case, the label should print `"OWNER"` instead of the department name. Modify the (_static_) `Badge.Print()` method to print a label for the owner: diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/numbers/.docs/hints.md index 2aa7128a00..2c7decd6b3 100644 --- a/exercises/concept/numbers/.docs/hints.md +++ b/exercises/concept/numbers/.docs/hints.md @@ -1,14 +1,14 @@ -### General +## General - [Numbers tutorial][numbers]. -### 1. Calculate the production rate per second +## 1. Calculate the production rate per second - Determining the success rate can be done through a [conditional statement][if-statement]. - C# allows for multiplication to be applied to two different number types (such as an `int` and a `double`). It will automatically return the "largest" data type. - Numbers can be compared using the built-in [comparison-][comparison-operators] and [equality operators][equality-operators]. -### 2. Calculate the number of working items produced per second +## 2. Calculate the number of working items produced per second - Whereas an `int` can be automatically converted to a `double`, the reverse does not hold. The reason for this is that an `int` has less precision than a `double` so rounding has to be applied, also the range of numbers an `int` can represent is smaller than a `double`. To force this conversion, one can either use one of the [`Convert` class' methods][convert-class] or [cast to an int][cast-int]. diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/numbers/.docs/instructions.md index 190d5dc4a1..e539f6fbc9 100644 --- a/exercises/concept/numbers/.docs/instructions.md +++ b/exercises/concept/numbers/.docs/instructions.md @@ -9,7 +9,7 @@ At its lowest speed (`1`), `221` cars are produced each hour. The production inc You have two tasks. -### 1. Calculate the production rate per hour +## 1. Calculate the production rate per hour Implement the (_static_) `AssemblyLine.ProductionRatePerHour()` method to calculate the assembly line's production rate per hour, taking into account its success rate: @@ -20,7 +20,7 @@ AssemblyLine.ProductionRatePerHour(6) Note that the value returned is a `double`. -### 2. Calculate the number of working items produced per minute +## 2. Calculate the number of working items produced per minute Implement the (_static_) `AssemblyLine.WorkingItemsPerMinute()` method to calculate how many working cars are produced per minute: diff --git a/exercises/concept/properties/.docs/hints.md b/exercises/concept/properties/.docs/hints.md index 9643459c3b..021e74b7f4 100644 --- a/exercises/concept/properties/.docs/hints.md +++ b/exercises/concept/properties/.docs/hints.md @@ -1,25 +1,25 @@ -### General +## General - [Properties][docs.microsoft.com-properties] - [Using Properties][docs.microsoft.com-using-properties] -### 1. Allow the weight to be set on the weighing machine +## 1. Allow the weight to be set on the weighing machine A property with a private [backing field][docs.microsoft.com-properties-with-backing-fields] is appropriate here. -### 2. Ensure that a negative input weight is rejected. +## 2. Ensure that a negative input weight is rejected. Add [validation][stackoverflow.com-validating-properties] to the `InputWeight`'s `set` accessor to throw an exception. -### 3. Allow the US weight to be retrieved +## 3. Allow the US weight to be retrieved A property can return a reference to an object. -### 4. Allow the machine's units to be set to pounds +## 4. Allow the machine's units to be set to pounds `Units` is a good candidate for an [auto-implemented property][docs.microsoft.com-auto-implemented-properties]. -### 5. Allow a tare adjustment to be applied to the weighing machine +## 5. Allow a tare adjustment to be applied to the weighing machine Accessors can have [different access levels][docs.microsoft.com-properties-and-restricted-access] to each other. diff --git a/exercises/concept/properties/.docs/instructions.md b/exercises/concept/properties/.docs/instructions.md index c0ef53d0b4..2379deee47 100644 --- a/exercises/concept/properties/.docs/instructions.md +++ b/exercises/concept/properties/.docs/instructions.md @@ -29,7 +29,7 @@ For Example: You have 5 tasks each of which requires you to implement one or more properties: -### 1. Allow the weight to be set on the weighing machine +## 1. Allow the weight to be set on the weighing machine Implement the `WeigingMachine.InputWeight` property to allow the weight to be get and set: @@ -40,7 +40,7 @@ wm.InputWeight = 60m; // => wm.InputWeight == 60m ``` -### 2. Ensure that a negative input weight is rejected +## 2. Ensure that a negative input weight is rejected Add validation to the `WeighingMachine.InputWeight` property to throw an `ArgumentOutOfRangeException` when trying to set it to a negative weight: @@ -49,7 +49,7 @@ var wm = new WeighingMachine(); wm.InputWeight = -10m; // Throws an ArgumentException ``` -### 3. Allow the US weight to be retrieved +## 3. Allow the US weight to be retrieved Implement the `WeighingMachine.USDisplayWeight` property and the `USWeight` class: @@ -61,7 +61,7 @@ var usw = wm.USDisplayWeight; // => usw.Pounds == 132 && usw.Ounces == 4 ``` -### 4. Allow the machine's units to be set to pounds +## 4. Allow the machine's units to be set to pounds Implement the `WeighingMachine.Units` property: @@ -74,7 +74,7 @@ var usw = wm.USDisplayWeight; // => usw.Pounds == 175 && usw.Ounces == 8 ``` -### 5. Allow a tare adjustment to be applied to the weighing machine +## 5. Allow a tare adjustment to be applied to the weighing machine Implement the `WeighingMachine.TareAdjustment` and `WeighingMachine.DisplayWeight` properties: diff --git a/exercises/concept/properties/.docs/introduction.md b/exercises/concept/properties/.docs/introduction.md index e2d8f452fc..f81e97a68d 100644 --- a/exercises/concept/properties/.docs/introduction.md +++ b/exercises/concept/properties/.docs/introduction.md @@ -18,7 +18,7 @@ accessor and vice versa. A property doesn't have to have both accessors, it can The basic syntax to express properties can take two forms: -###### Field/Expression Backed Properties: +#### Field/Expression Backed Properties: ```csharp private int myField; @@ -29,7 +29,7 @@ public int MyProperty } ``` -###### Auto-implemented Properties +#### Auto-implemented Properties ``` public int MyProperty { get; private set; } = 42; diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/strings/.docs/hints.md index c9d469cc52..4ab8ad369a 100644 --- a/exercises/concept/strings/.docs/hints.md +++ b/exercises/concept/strings/.docs/hints.md @@ -1,18 +1,18 @@ -### General +## General - The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction to C# `string`s. - The `string` class has many useful [built-in methods][docs-string-methods]. -### 1. Get message from a log line +## 1. Get message from a log line - Different options to search for text in a string are explored in [this tutorial][tutorial-docs.microsoft.com-search-text-in-string]. - Removing white space is [built-in][tutorial-docs.microsoft.com-trim-white-space]. -### 2. Get log level from a log line +## 2. Get log level from a log line - Changing a `string`'s casing is explored in [this tutorial][tutorial-docs.microsoft.com-changing-case]. -### 3. Reformat a log line +## 3. Reformat a log line - There are several ways to [concatenate strings][tutorial-docs.microsoft.com-concatenate-strings], but the preferred one is usually [string interpolation][tutorial-csharp.net-string-interpolation]. diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/strings/.docs/instructions.md index 439d3dc55c..d8a68cf1c2 100644 --- a/exercises/concept/strings/.docs/instructions.md +++ b/exercises/concept/strings/.docs/instructions.md @@ -10,7 +10,7 @@ There are three different log levels: You have three tasks, each of which will take a log line and ask you to do something with it. -### 1. Get message from a log line +## 1. Get message from a log line Implement the (_static_) `LogLine.Message()` method to return a log line's message: @@ -26,7 +26,7 @@ LogLine.Message("[WARNING]: Disk almost full\r\n") // => "Disk almost full" ``` -### 2. Get log level from a log line +## 2. Get log level from a log line Implement the (_static_) `LogLine.LogLevel()` method to return a log line's log level, which should be returned in lowercase: @@ -35,7 +35,7 @@ LogLine.LogLevel("[ERROR]: Invalid operation") // => "error" ``` -### 3. Reformat a log line +## 3. Reformat a log line Implement the (_static_) `LogLine.Reformat()` method that reformats the log line, putting the message first and the log level after it in parentheses: From dcc27442ddf0121dd3c0c614d3f8d88664e29cc2 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 26 May 2020 11:29:34 +0100 Subject: [PATCH 134/327] add dictionaries exercise * WIP * added tasks * tests complete * added initial draft of code * hints substantially complete * some work on after.md * extra tests * dictionaries - tweaked docs * dictionaries - formatting of code files * dictionaries - applied prettier * dictionaries - completing docs * dictionaries - completing docs * dictionaries - fixing github action issues * dictionaries - included proj file * dictionaries - proofed * dictionaries - proofed * dictionaries - proofed * dictionaries - added prereq * dictionaries - fixed typo * dictionaries - prettier * Update languages/exercises/concept/README.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/reference/README.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/introduction.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/DictionariesTest.cs Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * dictionaries - rounded out code review changes * Update languages/exercises/concept/dictionaries/.docs/introduction.md Co-authored-by: Erik Schierboom * dictionaries - prettying * dictionaries - prettying * dictionaries - prettying Co-authored-by: mikedamay Co-authored-by: Erik Schierboom --- exercises/concept/dictionaries/.docs/after.md | 31 +++++ exercises/concept/dictionaries/.docs/hints.md | 54 +++++++++ .../dictionaries/.docs/instructions.md | 109 ++++++++++++++++++ .../dictionaries/.docs/introduction.md | 45 ++++++++ .../concept/dictionaries/.meta/Example.cs | 81 +++++++++++++ .../concept/dictionaries/.meta/config.json | 8 ++ .../concept/dictionaries/.meta/design.md | 60 ++++++++++ .../concept/dictionaries/Dictionaries.cs | 52 +++++++++ .../concept/dictionaries/Dictionaries.csproj | 13 +++ .../concept/dictionaries/DictionariesTest.cs | 103 +++++++++++++++++ 10 files changed, 556 insertions(+) create mode 100644 exercises/concept/dictionaries/.docs/after.md create mode 100644 exercises/concept/dictionaries/.docs/hints.md create mode 100644 exercises/concept/dictionaries/.docs/instructions.md create mode 100644 exercises/concept/dictionaries/.docs/introduction.md create mode 100644 exercises/concept/dictionaries/.meta/Example.cs create mode 100644 exercises/concept/dictionaries/.meta/config.json create mode 100644 exercises/concept/dictionaries/.meta/design.md create mode 100644 exercises/concept/dictionaries/Dictionaries.cs create mode 100644 exercises/concept/dictionaries/Dictionaries.csproj create mode 100644 exercises/concept/dictionaries/DictionariesTest.cs diff --git a/exercises/concept/dictionaries/.docs/after.md b/exercises/concept/dictionaries/.docs/after.md new file mode 100644 index 0000000000..90fb70e4ea --- /dev/null +++ b/exercises/concept/dictionaries/.docs/after.md @@ -0,0 +1,31 @@ +Dictionaries, like their equivalents in other languages such as maps or associative arrays, store key/value pairs such that a value can be retrieved or changed directly by passing the key to the dictionary's indexer property. + +In addition key/value pairs can be added and removed from the dictionary. Keys, values and key/value pairs can be enumerated. + +Values can be objects of any C# type, which includes primitives, structs _and_ classes. + +The Dictionary object allows keys to be objects of any type. However to ensure correct behavior at runtime keys must have an appropriate hashcode as returned by [GetHashCode][gethashcode]. + +A dictionary instance cannot be safely accessed by more than one thread (not thread-safe). [ConcurrentDictionary][concurrent-dictionary] is available for multi-threading situations. + +See also [HashSet][hashset], [ConcurrentDictionary][concurrent-dictionary], [SortedDictionary][sorted-dictionary]. + +Whilst there is no non-generic version of Dictionary a number of classes remain in the library to support a non-generic map. You need to be aware of the non-generic IDictionary and Hashtable mainly so that you know them when you see them. It is unlikely you would have to use them other than in maintaining an old code base. + +You will often want to expose and access the dictionary by its [`IDictionary`][idictionary] interface. + +Note that because of the nature of [indexer properties][indexer-properties] primitive values can be modified in place, such as: + +```csharp +nums["some-number"] = 3; +nums["some-number"]++; +// nums["some-number"] == 4 + +``` + +[concurrent-dictionary]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-3.1 +[hashset]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[gethashcode]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 +[sorted-dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netcore-3.1 +[idictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.idictionary-2?view=netcore-3.1 +[indexer-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/ diff --git a/exercises/concept/dictionaries/.docs/hints.md b/exercises/concept/dictionaries/.docs/hints.md new file mode 100644 index 0000000000..4b470880a4 --- /dev/null +++ b/exercises/concept/dictionaries/.docs/hints.md @@ -0,0 +1,54 @@ +### 1. Create a new dictionary + +A dictionary is like any other class. You simply 'new' it to create an empty instance. + +### 2. Create a pre-populated dictionary + +Although it's possible to populate a dictionary by repeatedly adding items, dictionaries can be initialized statically. + +See [this article][dictionary_static_initialization]. + +### 3. Add a country to an empty dictionary + +See [Add][dictionary_add]. Pass in the dictionary returned by task 1 as a parameter. + +### 4. Add a country to an existing dictionary + +There is no substantial difference between adding an item to an empty or initialized dictionary. Pass in the dictionary returned by task 2 as a parameter. + +### 5. Get the country name matching a country Code + +See [this article][dictionary_item]. + +### 6. Attempt to get country name for a non-existent country code + +You need to [detect][dictionary_contains_key] whether the country is present in the dictionary. + +### 7. Attempt to get country name for a non-existent country code + +You can combine what you've learnt in Tasks 5 and 6 to solve this one. + +### 8. Update a country name + +Again [this article][dictionary_item] applies. + +### 9. Attempt to ypdate name of country that is not in the dictionary + +This is very similar to task 7. + +### 10. Remove a country from the dictionary + +See [this article][dictionary_remove]. + +### 11. Find the country with the longest name + +See the [values collection][dictionary_values], [string length][string_length] and [foreach][foreach]. + +[dictionary_static_initialization]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-a-dictionary-with-a-collection-initializer +[dictionary_add]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2.add?view=netcore-3.1 +[dictionary_item]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.dictionary-2.item?view=netcore-3.1 +[dictionary_contains_key]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.dictionary-2.containskey?view=netcore-3.1 +[dictionary_remove]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.dictionary-2.remove?view=netcore-3.1 +[dictionary_values]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.dictionary-2.values?view=netcore-3.1 +[foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in +[string_length]: https://docs.microsoft.com/en-gb/dotnet/api/system.string.length?view=netcore-3.1#System_String_Length diff --git a/exercises/concept/dictionaries/.docs/instructions.md b/exercises/concept/dictionaries/.docs/instructions.md new file mode 100644 index 0000000000..d63b7de736 --- /dev/null +++ b/exercises/concept/dictionaries/.docs/instructions.md @@ -0,0 +1,109 @@ +In this exercise you'll be writing code to keep track of international dialling codes via an international dialing code dictionary. + +The dictionary uses an integer for its keys (the dialing code) and a string (country name) for its values. + +You have 11 tasks which involve DialingCodes. + +### 1. Create a new dictionary + +```csharp +DialingCodes.GetEmptyDictionary(); +// empty dictionary +``` + +### 2. Create a pre-populated dictionary + +There exists a pre-populated dictionary which contains the following 3 dialing codes: "United States of America" which has a code of 1, "Brazil" which has a code of 55 and "India" which has a code of 91. Implement the (static) `DialingCodes.GetExistingDictionary()` method to return the pre-propulated dictionary: + +```csharp +DialingCodes.GetExistingDictionary(); +// 1 => "United States of America", 55 => "Brazil", 91 => "India" +``` + +### 3. Add a country to an empty dictionary + +Add "United Kingdom" with a dialing code of 44: + +```csharp +DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); +// 44 => "United Kingdom" +``` + +### 4. Add a country to an dxisting dictionary + +Add "United Kindom" with a dialing code of 44 to the dictionary created in task 2: + +```csharp +DialingCodes.AddCountryToExistingDictionary(DialingCodes.GetExistingDictionary(), + 44, "United Kingdom"); +// 1 => "United States of America", 44 => "United Kingdom", 55 => "Brazil", 91 => "India" +``` + +### 5. Get the country name matching a country code + +Check that a country with the country name for dialing code 55 + +```csharp +DialingCodes.GetCountryNameFromDictionary( + DialingCodes.GetExistingDictionary(), 55); +// "Brazil" +``` + +### 6. Check that a country exists in the dictionary + +Check that a record for Brazil exists in the dictionary created in task 2 + +```csharp +DialingCodes.CheckCodeExists(DialingCodes.GetExistingDictionary(), 55); +// true +``` + +### 7. Attempt to get country name for a non-existent country code + +Request the country name for a code that is not in the existing dictionary, e.g. 999. An empty string should be returned: + +```csharp +DialingCodes.GetCountryNameFromDictionary( + DialingCodes.GetExistingDictionary(), 999); +// string.Empty +``` + +### 8. Update a country name + +Change the name of "United States of America" to "Les États-Unis": + +```csharp +DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "Les États-Unis"); +// 1 => "Les États-Unis", 55 => "Brazil", 91 => "India" +``` + +### 9. Attempt to update name of country that is not in the dictionary + +Try to change the name of a country with a code that is not in the dictionary e.g. 999. This should result in no change to the dictionary: + +```csharp +DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 999, "Newlands"); +// 1 => "United States of America", 55 => "Brazil", 91 => "India" +``` + +### 10. Remove a country from the dictionary + +Remove India from the dictionary: + +```csharp +DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 91); +// 1 => "United States of America", 55 => "Brazil" +``` + +### 11. Find the country with the longest name + +Process the values in the dictionary to find the one with the longest name: + +```csharp +DialingCodes.FindLongestCountryName( + DialingCodes.GetExistingDictionary()); +// "United States of America" +``` diff --git a/exercises/concept/dictionaries/.docs/introduction.md b/exercises/concept/dictionaries/.docs/introduction.md new file mode 100644 index 0000000000..5619ea3abd --- /dev/null +++ b/exercises/concept/dictionaries/.docs/introduction.md @@ -0,0 +1,45 @@ +A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the ditionary its associated value is returned. It has the same role as maps or associative arrays do in other languages. + +A dictionary can be created as follows: + +```csharp +new Dictionary +{ + {1, "One"}, + {2, "Two"} +}; +// 1 => "One", 2 => "Two" +``` + +Note that the key and value types are part of the definition of the dictionary. + +Once constructed, entries can be added or removed from a dictionary using its built-in methods. + +Retrieving or updating values in a dictionary is done by indexing into the dictionary using a key: + +```csharp +var numbers = new Dictionary +{ + {1, "One"}, + {2, "Two"} +}; + +// Set the value of the element with key 2 to "Deux" +numbers[2] = "Deux"; + +// Get the value of the element with key 2 +numbers[2]; +// "Deux" +``` + +You can test if a value exists in the dictionary with: + +```csharp +var dict = new Dictionary{/*...*/}; +dict.ContainsKey("some key that exists"); +// => true +``` + +Enumerating over a dictionary will enumerate over its key/value pairs. Dictionaries also have properties that allow enumerating over its keys or values. + +[indexer-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/ diff --git a/exercises/concept/dictionaries/.meta/Example.cs b/exercises/concept/dictionaries/.meta/Example.cs new file mode 100644 index 0000000000..528ffd9eb2 --- /dev/null +++ b/exercises/concept/dictionaries/.meta/Example.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; + +public static class DialingCodes_example +{ + public static Dictionary GetEmptyDictionary() + { + return new Dictionary(); + } + + public static Dictionary GetExistingDictionary() + { + return new Dictionary + { + {1, "United States of America"}, + {55, "Brazil"}, + {91, "India"} + }; + } + + public static Dictionary AddCountryToEmptyDictionary(int CountryCode, string CountryName) + { + return new Dictionary() { { CountryCode, CountryName } }; + } + + public static Dictionary AddCountryToExistingDictionary( + Dictionary existingDictionary, int countryCode, string countryName) + { + existingDictionary[countryCode] = countryName; + return existingDictionary; + } + + public static string GetCountryNameFromDictionary( + Dictionary existingDictionary, int countryCode) + { + if (existingDictionary.ContainsKey(countryCode)) + { + return existingDictionary[countryCode]; + } + else + { + return string.Empty; + } + } + public static Dictionary UpdateDictionary( + Dictionary existingDictionary, int countryCode, string countryName) + { + if (existingDictionary.ContainsKey(countryCode)) + { + existingDictionary[countryCode] = countryName; + } + + return existingDictionary; + } + + public static Dictionary RemoveCountryFromDictionary( + Dictionary existingDictionary, int countryCode) + { + existingDictionary.Remove(countryCode); + return existingDictionary; + } + + public static bool CheckCodeExists(Dictionary existingDictionary, int countryCode) + { + return existingDictionary.ContainsKey(countryCode); + } + + public static string FindLongestCountryName(Dictionary existingDictionary) + { + string longestCountryName = string.Empty; + foreach (string countryName in existingDictionary.Values) + { + if (countryName.Length > longestCountryName.Length) + { + longestCountryName = countryName; + } + } + + return longestCountryName; + } +} diff --git a/exercises/concept/dictionaries/.meta/config.json b/exercises/concept/dictionaries/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/dictionaries/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md new file mode 100644 index 0000000000..1b51e6ab20 --- /dev/null +++ b/exercises/concept/dictionaries/.meta/design.md @@ -0,0 +1,60 @@ +## Goal + +The goal of this exercise is to teach the student the basics of the Concept of Dictionaries in [C#][dictionaries-docs]. + +## Learning objectives + +- Know of the existence of the `Dictionary` type. +- Know how to define a dictionary. +- Know how to add and updated elements in a dictionary. +- Know how to access elements in a dictionary by key. +- Know how to iterate over elements in a dictionary. +- Know some basic dictionary functions (like checking if a key exists). + +## Out of scope + +- Generic functions. +- Generic constraints. +- Memory and performance characteristics. +- LINQ. +- Concurrency issues. +- Co-/contravariance. +- Equality. +- The `Lookup` type. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `dictionaries`: know of the existence of the `Dictionary` type; know how to define a dictionary; know how to add and updated elements in a dictionary; know how to access elements in a dictionary by key; know how to iterate over elements in a dictionary; know some basic dictionary functions. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `foreach-loops`: know how to use a `foreach-loop` to iterate over a collection. +- `generic-types`: know how generic types work. +- `strings`: know how to discover string length +- `indexers`: usage and behavior of indexer properties + +## Representer + +This exercise does not require any specific representation logic to be added to the [representer][representer]. + +## Analyzer + +This exercise does not require any specific analyzer logic to be added to the [analyzer][analyzer]. + +[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/master/docs/maintainers/generic-how-to-implement-a-concept-exercise.md +[implemented-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md#implemented-exercises +[reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs +[reference-dictionary]: https://github.com/exercism/v3/blob/master/reference/types/dictionary.md +[reference-example]: https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point +[design-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/design.md +[config.json-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/config.json +[concept-exercises]: https://github.com/exercism/v3/blob/master/docs/concept-exercises.md +[dictionaries-docs]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netcore-3.1 +[dictionaries-tutorial]: https://csharp.net-tutorials.com/collections/dictionaries/ diff --git a/exercises/concept/dictionaries/Dictionaries.cs b/exercises/concept/dictionaries/Dictionaries.cs new file mode 100644 index 0000000000..53ea034a67 --- /dev/null +++ b/exercises/concept/dictionaries/Dictionaries.cs @@ -0,0 +1,52 @@ +using System; +using System.Collections.Generic; + +public class DialingCodes +{ + public static Dictionary GetEmptyDictionary() + { + throw new NotImplementedException($"Please implement the (static) GetEmptyDictionary() method"); + } + + public static Dictionary GetExistingDictionary() + { + throw new NotImplementedException($"Please implement the (static) GetExistingDictionary() method"); + } + + public static Dictionary AddCountryToEmptyDictionary(int CountryCode, string CountryName) + { + throw new NotImplementedException($"Please implement the (static) AddCountryToEmptyDictionary() method"); + } + + public static Dictionary AddCountryToExistingDictionary( + Dictionary existingDictiopnary, int countryCode, string CountryName) + { + throw new NotImplementedException($"Please implement the (static) AddCountryToExistingDictionary() method"); + } + + public static string GetCountryNameFromDictionary( + Dictionary existingDictionary, int countryCode) + { + throw new NotImplementedException($"Please implement the (static) GetCountryNameFromDictionary() method"); + } + public static Dictionary UpdateDictionary( + Dictionary existingDictionary, int countryCode, string countryName) + { + throw new NotImplementedException($"Please implement the (static) UpdateDictionary() method"); + } + + public static Dictionary RemoveCountryFromDictionary( + Dictionary existingDictionary, int countryCode) + { + throw new NotImplementedException($"Please implement the (static) RemoveCountryFromDictionary() method"); + } + public static bool CheckCodeExists(Dictionary existingDictionary, int countryCode) + { + throw new NotImplementedException($"Please implement the (static) CheckCodeExists() method"); + } + + public static string FindLongestCountryName(Dictionary existingDictionary) + { + throw new NotImplementedException($"Please implement the (static) FindLongestCountryName() method"); + } +} diff --git a/exercises/concept/dictionaries/Dictionaries.csproj b/exercises/concept/dictionaries/Dictionaries.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/dictionaries/Dictionaries.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/dictionaries/DictionariesTest.cs b/exercises/concept/dictionaries/DictionariesTest.cs new file mode 100644 index 0000000000..e4ad77f62b --- /dev/null +++ b/exercises/concept/dictionaries/DictionariesTest.cs @@ -0,0 +1,103 @@ +using Xunit; + +public class DialingCodesTest +{ + [Fact] + public void Empty_dictionary() + { + Assert.Empty(DialingCodes.GetEmptyDictionary()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Existing_dictionary() + { + var idcd = DialingCodes.GetExistingDictionary(); + Assert.Equal(3, idcd.Count); + Assert.Equal("United States of America", idcd[1]); + Assert.Equal("Brazil", idcd[55]); + Assert.Equal("India", idcd[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_empty_dictionary() + { + var idcd = DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); + Assert.Equal(1, idcd.Count); + Assert.Equal("United Kingdom", idcd[44]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary() + { + var idcd = DialingCodes.AddCountryToExistingDictionary( + DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); + Assert.Equal(4, idcd.Count); + Assert.Equal("United States of America", idcd[1]); + Assert.Equal("United Kingdom", idcd[44]); + Assert.Equal("Brazil", idcd[55]); + Assert.Equal("India", idcd[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Get_country_name_from_dictionary() + { + var countryName = DialingCodes.GetCountryNameFromDictionary( + DialingCodes.GetExistingDictionary(), 55); + Assert.Equal("Brazil", countryName); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Check_country_exists() + { + var exists = DialingCodes.CheckCodeExists( + DialingCodes.GetExistingDictionary(), 55); + Assert.True(exists); + } + [Fact(Skip = "Remove this Skip property to run this test")] + public void Try_to_get_non_existent_country_name_from_dictionary() + { + var countryName = DialingCodes.GetCountryNameFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal(string.Empty, countryName); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary() + { + var idcd = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "Les États-Unis"); + Assert.Equal(3, idcd.Count); + Assert.Equal("Les États-Unis", idcd[1]); + Assert.Equal("Brazil", idcd[55]); + Assert.Equal("India", idcd[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Try_to_update_country_name_in_dictionary_for_non_existent_country() + { + var idcd = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 999, "Newlands"); + Assert.Equal(3, idcd.Count); + Assert.Equal("United States of America", idcd[1]); + Assert.Equal("Brazil", idcd[55]); + Assert.Equal("India", idcd[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary() + { + var idcd = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 91); + Assert.Equal(2, idcd.Count); + Assert.Equal("United States of America", idcd[1]); + Assert.Equal("Brazil", idcd[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Longest_country_name() + { + var idcd = DialingCodes.FindLongestCountryName( + DialingCodes.GetExistingDictionary()); + Assert.Equal("United States of America", idcd); + } +} From c725076579db564f508eb966d838671093336dba Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 26 May 2020 12:46:44 +0200 Subject: [PATCH 135/327] Add digit separator notation to numbers exercise --- exercises/concept/numbers/.docs/after.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md index bd05dfab91..6b0d8dfe92 100644 --- a/exercises/concept/numbers/.docs/after.md +++ b/exercises/concept/numbers/.docs/after.md @@ -7,6 +7,16 @@ int i = 123; double d = 54.29; ``` +Both integers and floating-point numbers can use the `_` character as a _digit separator_, which can help when defining large numbers: + +```csharp +int largeInt = 1_000_000; +// => 1000000 + +double largeDouble = 9_876_543.21; +// => 9876543.21 +``` + Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.) and the [equality-][equality-operators] operator (`==`) and [inequality][equality-operators] operator (`!=`). ```csharp From 49b76e8d4da06b1f100f5e79dd4ec862767df78c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 27 May 2020 14:09:05 +0200 Subject: [PATCH 136/327] Introduce for loops in arrays exercise --- exercises/concept/arrays/.docs/after.md | 16 +++++++++---- exercises/concept/arrays/.docs/hints.md | 8 ++++--- .../concept/arrays/.docs/instructions.md | 8 +++---- .../concept/arrays/.docs/introduction.md | 24 +++++++++++++------ exercises/concept/arrays/.meta/Example.cs | 6 ++--- exercises/concept/arrays/.meta/design.md | 2 +- exercises/concept/arrays/Arrays.cs | 4 ++-- exercises/concept/arrays/ArraysTests.cs | 24 ++++--------------- 8 files changed, 48 insertions(+), 44 deletions(-) diff --git a/exercises/concept/arrays/.docs/after.md b/exercises/concept/arrays/.docs/after.md index 80ee0f5c8c..3c076905f7 100644 --- a/exercises/concept/arrays/.docs/after.md +++ b/exercises/concept/arrays/.docs/after.md @@ -1,11 +1,10 @@ -Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: +Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: ```csharp // Declare array with explicit size (size is 2) int[] twoInts = new int[2]; -// Assign first and second element by index -twoInts[0] = 7; +// Assign second element by index twoInts[1] = 8; // Retrieve the second element by index @@ -26,7 +25,7 @@ int[] threeIntsV3 = { 4, 9, 7 }; Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. -An array is also a _collection_, which means that you can iterate over all its values using a [`foreach` loop][foreach-statement]: +An array is also a _collection_, which means that you can iterate over _all_ its values using a [`foreach` loop][foreach-statement]: ```csharp char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; @@ -58,6 +57,7 @@ However, generally a `foreach` loop is preferrable over a `for` loop for the fol - A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. - A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. +- A `foreach` loop is foolproof, whereas with `for` loops it is easy to have an off-by-one error. - A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: @@ -72,6 +72,14 @@ foreach (char vowel in vowels) } ``` +A `for` loop does have some advantages over a `foreach` loop: + +- You can start or stop at the index you want. +- You can use any (boolean) termination condition you want. +- You can skip elements by customizing the incrementing of the loop variable. +- You can process collections from back to front by counting down. +- You can use `for` loops in scenarios that don't involve collections. + [implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays [array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays [single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/arrays/.docs/hints.md index 0bd9f555f9..9c9cc3280e 100644 --- a/exercises/concept/arrays/.docs/hints.md +++ b/exercises/concept/arrays/.docs/hints.md @@ -21,11 +21,12 @@ - The `Array` class has a [built-in method][array-indexof] that returns the first index where the element is found, or -1 if no matching element was found. -## 5. Calculate the total number of visiting birds +## 5. Calculate the number of visiting birds for the first number of days -- A variable can be used to hold the total number of visiting birds. -- The array can be iterated over using a [`foreach` loop][array-foreach]. +- A variable can be used to hold the count for the number of visiting birds. +- The array can be iterated over using a [`for` loop][for-statement]. - The variable can be updated inside the loop. +- Remember: arrays are indexed from `0`. ## 6. Calculate the number of busy days @@ -41,3 +42,4 @@ [array-indexof]: https://docs.microsoft.com/en-us/dotnet/api/system.array.indexof?view=netcore-3.1#System_Array_IndexOf_System_Array_System_Object_ [if-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else [array-length]: https://docs.microsoft.com/en-us/dotnet/api/system.array.length?view=netcore-3.1 +[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/arrays/.docs/instructions.md index 3e3ee40817..c7946b8f79 100644 --- a/exercises/concept/arrays/.docs/instructions.md +++ b/exercises/concept/arrays/.docs/instructions.md @@ -45,15 +45,15 @@ birdCount.HasDayWithoutBirds(); // => true ``` -## 5. Calculate the total number of visiting birds +## 5. Calculate the number of visiting birds for the first number of days -Implement the `BirdCount.Total()` method to return the total number of birds that have visited your garden: +Implement the `BirdCount.CountForFirstDays()` method that returns the number of birds that have visited your garden from the start of the week, but limit the count to the specified number of days from the start of the week. ```csharp int[] birdsPerDay = { 2, 5, 0, 7, 4, 1 }; var birdCount = new BirdCount(birdsPerDay); -birdCount.Total(); -// => 19 +birdCount.CountForFirstDays(4); +// => 14 ``` ## 6. Calculate the number of busy days diff --git a/exercises/concept/arrays/.docs/introduction.md b/exercises/concept/arrays/.docs/introduction.md index 4000fb2a48..b285eb638b 100644 --- a/exercises/concept/arrays/.docs/introduction.md +++ b/exercises/concept/arrays/.docs/introduction.md @@ -1,18 +1,14 @@ -In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: +In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: ```csharp // Declare array with explicit size (size is 2) int[] twoInts = new int[2]; -// Assign first and second element by index -twoInts[0] = 7; +// Assign second element by index twoInts[1] = 8; // Retrieve the second element by index twoInts[1] == 8; // => true - -// Check the length of the array -twoInts.Length == 2; // => true ``` Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: @@ -26,7 +22,7 @@ int[] threeIntsV3 = { 4, 9, 7 }; Arrays can be manipulated by either calling an array instance's methods or properties, or by using the static methods defined in the `Array` class. -The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over all its values using a `foreach` loop: +The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over _all_ its values using a `foreach` loop: ```csharp char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; @@ -39,3 +35,17 @@ foreach (char vowel in vowels) // => aeiou ``` + +If you want more control over which values to iterate over, a `for` loop can be used: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +for (int i = 0; i < 3; i++) +{ + // Output the vowel + System.Console.Write(vowels[i]); +} + +// => aei +``` diff --git a/exercises/concept/arrays/.meta/Example.cs b/exercises/concept/arrays/.meta/Example.cs index d2e947c966..b3a8ed7fb1 100644 --- a/exercises/concept/arrays/.meta/Example.cs +++ b/exercises/concept/arrays/.meta/Example.cs @@ -29,13 +29,13 @@ public bool HasDayWithoutBirds() return Array.IndexOf(birdsPerDay, 0) != -1; } - public int Total() + public int CountForFirstDays(int numberOfDays) { var total = 0; - foreach (var count in birdsPerDay) + for (var i = 0; i < numberOfDays; i++) { - total += count; + total += birdsPerDay[i]; } return total; diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 39aa42e300..88e932e9bf 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -33,6 +33,7 @@ Of the many available C# collection types, we chose to use the `array` collectio This Concepts Exercise's Concepts are: - `arrays`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to update an element in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). +- `for-loops`: know how to use a `for` loop to do iteration. - `foreach-loops`: know how to iterate over a collection. ## Prequisites @@ -40,7 +41,6 @@ This Concepts Exercise's Concepts are: This exercise's prerequisites Concepts are: - `classes`: know how to work with fields. -- `for-loops`: know what a `for` loop is. - `booleans`: know what a `bool` is. - `basics`: know how to work with `integers` and how to assign and update variables. diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/arrays/Arrays.cs index bfb04d17c0..fc7fc642c0 100644 --- a/exercises/concept/arrays/Arrays.cs +++ b/exercises/concept/arrays/Arrays.cs @@ -29,9 +29,9 @@ public bool HasDayWithoutBirds() throw new NotImplementedException("Please implement the BirdCount.HasDayWithoutBirds() method"); } - public int Total() + public int CountForFirstDays(int numberOfDays) { - throw new NotImplementedException("Please implement the BirdCount.Total() method"); + throw new NotImplementedException("Please implement the BirdCount.CountForFirstDays() method"); } public int BusyDays() diff --git a/exercises/concept/arrays/ArraysTests.cs b/exercises/concept/arrays/ArraysTests.cs index 697cca5293..13621ee0a8 100644 --- a/exercises/concept/arrays/ArraysTests.cs +++ b/exercises/concept/arrays/ArraysTests.cs @@ -59,19 +59,19 @@ public void Increment_todays_count_with_multiple_previous_visits() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Total_for_disappointing_week() + public void Count_for_first_two_days_of_disappointing_week() { var counts = new int[] { 0, 0, 1, 0, 0, 1, 0 }; var birdCount = new BirdCount(counts); - Assert.Equal(2, birdCount.Total()); + Assert.Equal(1, birdCount.CountForFirstDays(3)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Total_for_busy_week() + public void Count_for_first_six_days_of_busy_week() { var counts = new int[] { 5, 9, 12, 6, 8, 8, 17 }; var birdCount = new BirdCount(counts); - Assert.Equal(65, birdCount.Total()); + Assert.Equal(48, birdCount.CountForFirstDays(6)); } [Fact(Skip = "Remove this Skip property to run this test")] @@ -89,20 +89,4 @@ public void Busy_days_for_busy_week() var birdCount = new BirdCount(counts); Assert.Equal(5, birdCount.BusyDays()); } - - [Fact(Skip = "Remove this Skip property to run this test")] - public void Has_day_without_birds_with_day_without_birds() - { - var counts = new int[] { 5, 5, 4, 0, 7, 6, 7 }; - var birdCount = new BirdCount(counts); - Assert.True(birdCount.HasDayWithoutBirds()); - } - - [Fact(Skip = "Remove this Skip property to run this test")] - public void Has_day_without_birds_with_no_day_without_birds() - { - var counts = new int[] { 4, 5, 9, 10, 9, 4, 3 }; - var birdCount = new BirdCount(counts); - Assert.False(birdCount.HasDayWithoutBirds()); - } } From 96b2539198e94351a1c866894d393ce58c0fdce1 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 29 May 2020 09:45:32 +0100 Subject: [PATCH 137/327] Add related topics to arrays exercise Add related topics to arrays exercise --- exercises/concept/arrays/.docs/after.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/exercises/concept/arrays/.docs/after.md b/exercises/concept/arrays/.docs/after.md index 3c076905f7..4d5bc15209 100644 --- a/exercises/concept/arrays/.docs/after.md +++ b/exercises/concept/arrays/.docs/after.md @@ -80,6 +80,13 @@ A `for` loop does have some advantages over a `foreach` loop: - You can process collections from back to front by counting down. - You can use `for` loops in scenarios that don't involve collections. +Related Topics: + +- You should be aware that C# supports [multi-dimensional arrays][multi-dimensional-arrays] like `int[,] arr = new int[10, 5]` which can be very useful. +- You should also be aware that you can instantiate objects of type [`System.Array`][system-array-object] with `Array.CreateInstance`. Such objects are of little use - mainly for interop with VB.NET code. They are not interchangeable with standard arrays (`T[]`). They can have a non-zero lower bound. + +Both the above topics are discussed more fully in a later exercise. + [implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays [array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays [single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays @@ -89,3 +96,5 @@ A `for` loop does have some advantages over a `foreach` loop: [foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in [for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for [break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[multi-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays +[system-array-object]: https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_ From 063c1fe4062f5f77d168589be685f9d3f49fd35e Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 29 May 2020 11:23:28 +0200 Subject: [PATCH 138/327] Remove top-level header from design.md files --- exercises/concept/arrays/.meta/design.md | 2 -- exercises/concept/basics/.meta/design.md | 2 -- exercises/concept/booleans/.meta/design.md | 2 -- exercises/concept/classes/.meta/design.md | 2 -- exercises/concept/constructors/.meta/design.md | 2 -- exercises/concept/datetimes/.meta/design.md | 2 -- exercises/concept/enums/.meta/design.md | 2 -- exercises/concept/flag-enums/.meta/design.md | 2 -- exercises/concept/floating-point-numbers/.meta/design.md | 2 -- exercises/concept/inheritance/.meta/design.md | 2 -- exercises/concept/method-overloading/.meta/design.md | 2 -- exercises/concept/nullability/.meta/design.md | 2 -- exercises/concept/numbers/.meta/design.md | 2 -- exercises/concept/properties/.meta/design.md | 2 -- exercises/concept/strings/.meta/design.md | 2 -- 15 files changed, 30 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 88e932e9bf..40f4c59ee4 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of the Concept of Arrays in C#. diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index eeda578515..f18f47a3ff 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of programming in C#. diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/booleans/.meta/design.md index 5a60eefc7a..be888a51d1 100644 --- a/exercises/concept/booleans/.meta/design.md +++ b/exercises/concept/booleans/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of the Concept of Booleans in C#. diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index d28eb69745..b58fd0f05d 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the Concept of Classes in C#. diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md index d368b24492..47558a0bae 100644 --- a/exercises/concept/constructors/.meta/design.md +++ b/exercises/concept/constructors/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the Concept of Constructors in C#. diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/datetimes/.meta/design.md index d9560910e1..6df944546f 100644 --- a/exercises/concept/datetimes/.meta/design.md +++ b/exercises/concept/datetimes/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of the Concept of Dates through [C#][docs.microsoft.com-datetime]. diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index 7a3ae322df..445f54a5f2 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of the Concept of enums through [C#][docs.microsoft.com-enum]. diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md index e8a2134f87..b74806798d 100644 --- a/exercises/concept/flag-enums/.meta/design.md +++ b/exercises/concept/flag-enums/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student advanced aspects of the Concept of Enums in [C#][docs.microsoft.com-bitwise-and-shift-operators]. We'll do this in the form of working with [flag][docs.microsoft.com-flagsattribute] enums, which are enums whose values are interpreted as bitwise flags that can be manipulated through bitwise operations. diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index 5ce866204d..23fe05671f 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student how the Concept of floating-point numbers is implemented in [C#][docs.microsoft.com-floating-point-numeric-types]. It will show the available floating-point types and discuss their differences. diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index 3b2f40294c..f09f3bb565 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the Concept of Inheritance in C#. diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/method-overloading/.meta/design.md index e140306b08..6a2b5f6c07 100644 --- a/exercises/concept/method-overloading/.meta/design.md +++ b/exercises/concept/method-overloading/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the Concept of Method Overloading in C#. diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index 87e98ecfeb..ff3a94d4cf 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to introduce the student to the concept of [Nullability in C#][null-keyword]. diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index ed501403db..ca7a903ded 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student how the Concept of Numbers is implemented in [C#][docs.microsoft.com-numbers]. It will introduce this concept through the two most common numeric types in C#: `int` (whole number) and `double` (floating-point number). diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index d99118f85f..7fb56bd413 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to introduce the student to C# properties and to teach the student how the concept of properties is implemented in [C#][docs.microsoft.com-properties]. We'll teach the student about properties by having the student work with classes that expose contrasting forms of properties. The students will learn to work with properties with backing fields and auto-implemented properties. diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index 8a22042688..936959d1e2 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -1,5 +1,3 @@ -# Design - ## Goal The goal of this exercise is to teach the student the basics of the Concept of Strings in [C#][docs.microsoft.com-string]. From 7d2e7d4d776822a1ff06b58a4c5a654847011151 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 1 Jun 2020 14:02:30 +0200 Subject: [PATCH 139/327] Add compound assignment concept to flag-enums exercise --- exercises/concept/flag-enums/.docs/after.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/flag-enums/.docs/after.md b/exercises/concept/flag-enums/.docs/after.md index 1307a79801..adcce2f28d 100644 --- a/exercises/concept/flag-enums/.docs/after.md +++ b/exercises/concept/flag-enums/.docs/after.md @@ -57,7 +57,7 @@ features.HasFlag(PhoneFeatures.Call); // => false features.HasFlag(PhoneFeatures.Text); // => true ``` -The bitwise operators can also be used as [compound assignments][compound-operators], which are a shorthand notation where `x = op y` can be written as `x op= y`: +The bitwise operators can also be used as [compound assignments][compound-assignment], which are a shorthand notation where `x = op y` can be written as `x op= y`: ```csharp var features = PhoneFeatures.Call; @@ -85,4 +85,4 @@ enum PhoneFeatures : byte [bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- [binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals [has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 -[compound-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment +[compound-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment From 3cd3bfab84edefcf6ea3313d6cffbbd58e9ca797 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 1 Jun 2020 18:09:07 +0200 Subject: [PATCH 140/327] Improve elapsed time for basics exercise --- exercises/concept/basics/.docs/hints.md | 2 +- exercises/concept/basics/.docs/instructions.md | 6 +++--- exercises/concept/basics/.meta/Example.cs | 2 +- exercises/concept/basics/.meta/design.md | 2 +- exercises/concept/basics/Basics.cs | 2 +- exercises/concept/basics/BasicsTests.cs | 8 ++++---- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/exercises/concept/basics/.docs/hints.md b/exercises/concept/basics/.docs/hints.md index 5607ce2aed..e99d482a2a 100644 --- a/exercises/concept/basics/.docs/hints.md +++ b/exercises/concept/basics/.docs/hints.md @@ -21,7 +21,7 @@ - The method's parameter is an [integer][integers]. - You can use the [mathematical operator for multiplicaton][operators] to multiply values. -## 4. Calculate the total working time in minutes +## 4. Calculate the elapsed time in minutes - You need to define a [method][methods] with two parameters. - You have to [explicitly return an integer][return] from a method. diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/basics/.docs/instructions.md index baeaa1eccd..1934d59e32 100644 --- a/exercises/concept/basics/.docs/instructions.md +++ b/exercises/concept/basics/.docs/instructions.md @@ -32,12 +32,12 @@ lasagna.PreparationTimeInMinutes(2); // => 4 ``` -## 4. Calculate the total working time in minutes +## 4. Calculate the elapsed time in minutes -Define the `Lasagna.TotalTimeInMinutes()` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes in total you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. +Define the `Lasagna.ElapsedTimeInMinutes()` method that takes two parameters: the first parameter is the number of layers you added to the lasagna, and the second parameter is the number of minutes the lasagna has been in the oven. The function should return how many minutes you've worked on cooking the lasagna, which is the sum of the preparation time in minutes, and the time in minutes the lasagna has spent in the oven at the moment. ```csharp var lasagna = new Lasagna(); -lasagna.TotalTimeInMinutes(3, 20); +lasagna.ElapsedTimeInMinutes(3, 20); // => 26 ``` diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/basics/.meta/Example.cs index 554d34f6be..a8b2e6b813 100644 --- a/exercises/concept/basics/.meta/Example.cs +++ b/exercises/concept/basics/.meta/Example.cs @@ -15,7 +15,7 @@ public int PreparationTimeInMinutes(int numberOfLayers) return numberOfLayers * 2; } - public int TotalTimeInMinutes(int numberOfLayers, int actualMinutesInOven) + public int ElapsedTimeInMinutes(int numberOfLayers, int actualMinutesInOven) { return PreparationTimeInMinutes(numberOfLayers) + actualMinutesInOven; } diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index f18f47a3ff..d373b647dc 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -51,7 +51,7 @@ This exercise does not require any specific representation logic to be added to This exercise could benefit from the following rules added to the the [analyzer][analyzer]: - Verify that the `RemainingMinutesInOven()` method calls the `ExpectedMinutesInOven()` method. -- Verify that the `TotalTimeInMinutes()` method calls the `PreparationTimeInMinutes()` method. +- Verify that the `ElapsedTimeInMinutes()` method calls the `PreparationTimeInMinutes()` method. [analyzer]: https://github.com/exercism/csharp-analyzer [representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/basics/Basics.cs index 378ef7534a..da238a8870 100644 --- a/exercises/concept/basics/Basics.cs +++ b/exercises/concept/basics/Basics.cs @@ -6,5 +6,5 @@ class Lasagna // TODO: define the 'PreparationTimeInMinutes()' method - // TODO: define the 'TotalTimeInMinutes()' method + // TODO: define the 'ElapsedTimeInMinutes()' method } diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/basics/BasicsTests.cs index 0b0753d08f..d5438b287b 100644 --- a/exercises/concept/basics/BasicsTests.cs +++ b/exercises/concept/basics/BasicsTests.cs @@ -27,14 +27,14 @@ public void Preparation_time_in_minutes_for_multiple_layers() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Total_time_in_minutes_for_one_layer() + public void Elapsed_time_in_minutes_for_one_layer() { - Assert.Equal(32, new Lasagna().TotalTimeInMinutes(1, 30)); + Assert.Equal(32, new Lasagna().ElapsedTimeInMinutes(1, 30)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Total_time_in_minutes_for_multiple_layers() + public void Elapsed_time_in_minutes_for_multiple_layers() { - Assert.Equal(16, new Lasagna().TotalTimeInMinutes(4, 8)); + Assert.Equal(16, new Lasagna().ElapsedTimeInMinutes(4, 8)); } } From 3dea963ca5036a85058f07b1f7b6ce788ad18fe4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Mon, 1 Jun 2020 18:17:48 +0200 Subject: [PATCH 141/327] Remove unneeded representer and analyzer sections * Remove unneeded representer and analyzer sections * Remove unneeded text from design.md --- exercises/concept/arrays/.meta/design.md | 12 ------------ exercises/concept/basics/.meta/design.md | 7 ------- exercises/concept/booleans/.meta/design.md | 13 ------------- exercises/concept/classes/.meta/design.md | 15 --------------- exercises/concept/constructors/.meta/design.md | 15 --------------- exercises/concept/datetimes/.meta/design.md | 12 ------------ exercises/concept/dictionaries/.meta/design.md | 14 -------------- exercises/concept/enums/.meta/design.md | 12 ------------ exercises/concept/flag-enums/.meta/design.md | 2 -- .../floating-point-numbers/.meta/design.md | 12 ------------ exercises/concept/inheritance/.meta/design.md | 9 --------- .../concept/method-overloading/.meta/design.md | 9 --------- exercises/concept/nullability/.meta/design.md | 14 -------------- exercises/concept/numbers/.meta/design.md | 12 ------------ exercises/concept/properties/.meta/design.md | 2 -- exercises/concept/strings/.meta/design.md | 12 ------------ 16 files changed, 172 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 40f4c59ee4..5d94be436f 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -28,8 +28,6 @@ Of the many available C# collection types, we chose to use the `array` collectio ## Concepts -This Concepts Exercise's Concepts are: - - `arrays`: know of the existence of the `Array` type; know how to define an array; know how to access elements in an array by index; know how to update an element in an array by index; know how to iterate over elements in an array; know of some basic functions (like finding the index of an element in an array). - `for-loops`: know how to use a `for` loop to do iteration. - `foreach-loops`: know how to iterate over a collection. @@ -42,14 +40,4 @@ This exercise's prerequisites Concepts are: - `booleans`: know what a `bool` is. - `basics`: know how to work with `integers` and how to assign and update variables. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index d373b647dc..aa0074da78 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -34,18 +34,12 @@ The goal of this exercise is to teach the student the basics of programming in C ## Concepts -The Concepts this exercise unlocks are: - - `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. ## Prequisites There are no prerequisites. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - ## Analyzer This exercise could benefit from the following rules added to the the [analyzer][analyzer]: @@ -54,4 +48,3 @@ This exercise could benefit from the following rules added to the the [analyzer] - Verify that the `ElapsedTimeInMinutes()` method calls the `PreparationTimeInMinutes()` method. [analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/booleans/.meta/design.md index be888a51d1..f79135b851 100644 --- a/exercises/concept/booleans/.meta/design.md +++ b/exercises/concept/booleans/.meta/design.md @@ -14,8 +14,6 @@ The goal of this exercise is to teach the student the basics of the Concept of B ## Concepts -The Concepts this exercise unlocks are: - - `booleans`: know of the existence of the `bool` type and its two values; know about boolean operators and how to build logical expressions with them; know of the boolean operator precedence rules. ## Prequisites @@ -23,14 +21,3 @@ The Concepts this exercise unlocks are: This exercise's prerequisites Concepts are: - `basics`: know how to define methods. - -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index b58fd0f05d..86323fdb29 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -27,26 +27,11 @@ The goal of this exercise is to teach the student the Concept of Classes in C#. ## Concepts -This Concepts Exercise's Concepts are: - - `classes`: know what classes are; know what encapsulation is; know what fields are; know how to create an object; know how to update state through methods; know about the `void` type. ## Prequisites -This Concept Exercise's prerequisites Concepts are: - - `basics`: know how to define a basic class with basic methods. - `strings`: know how to do basic string interpolation. - `numbers`: know how to compare numbers. - `conditionals`: know how to do conditional logic. - -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md index 47558a0bae..7e2083ba7a 100644 --- a/exercises/concept/constructors/.meta/design.md +++ b/exercises/concept/constructors/.meta/design.md @@ -17,26 +17,11 @@ The goal of this exercise is to teach the student the Concept of Constructors in ## Concepts -This Concepts Exercise's Concepts are: - - `constructors`: know what constructors are; know how to define parameterless constructors; know how to define parameterized constructors; know how to use constructor overloading; know how to define private constructors. ## Prequisites -This Concept Exercise's prerequisites Concepts are: - - `classes`: know how to work with classes. - `numbers`: know how compare numbers. - `conditionals`: know how to do conditional logic. - `while-loops`: know how to use `while` loops. - -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/datetimes/.meta/design.md index 6df944546f..e70fb32ad3 100644 --- a/exercises/concept/datetimes/.meta/design.md +++ b/exercises/concept/datetimes/.meta/design.md @@ -22,8 +22,6 @@ The goal of this exercise is to teach the student the basics of the Concept of D ## Concepts -The Concepts this exercise unlocks are: - - `datetime`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa; know of the existence of the `DateTime` type; know of the individual, time-related properties. ## Prequisites @@ -34,14 +32,4 @@ This exercise's prerequisites Concepts are: - `strings`: dates are parsed from and converted to strings. - `classes`: know how to call a constructor. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-datetime]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md index 1b51e6ab20..8bfb4c7266 100644 --- a/exercises/concept/dictionaries/.meta/design.md +++ b/exercises/concept/dictionaries/.meta/design.md @@ -24,34 +24,20 @@ The goal of this exercise is to teach the student the basics of the Concept of D ## Concepts -This Concepts Exercise's Concepts are: - - `dictionaries`: know of the existence of the `Dictionary` type; know how to define a dictionary; know how to add and updated elements in a dictionary; know how to access elements in a dictionary by key; know how to iterate over elements in a dictionary; know some basic dictionary functions. ## Prequisites -This Concept Exercise's prerequisites Concepts are: - - `foreach-loops`: know how to use a `foreach-loop` to iterate over a collection. - `generic-types`: know how generic types work. - `strings`: know how to discover string length - `indexers`: usage and behavior of indexer properties -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific analyzer logic to be added to the [analyzer][analyzer]. - [how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/master/docs/maintainers/generic-how-to-implement-a-concept-exercise.md [implemented-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md#implemented-exercises [reference]: https://github.com/exercism/v3/blob/master/languages/csharp/reference/README.md#reference-docs [reference-dictionary]: https://github.com/exercism/v3/blob/master/reference/types/dictionary.md [reference-example]: https://github.com/exercism/v3/blob/master/reference/types/string.md#implementations -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [exercise-example]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/numbers-floating-point [design-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/design.md [config.json-example]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/numbers/.meta/config.json diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index 445f54a5f2..df456e5a11 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -21,8 +21,6 @@ After completing this exercise, the student should: ## Concepts -The Concepts this exercise unlocks are: - - `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert an `enum` to a `string`. - `pattern-matching-constants`: know how to use the `switch` statement to do constant pattern matching. @@ -33,14 +31,4 @@ This exercise's prerequisites Concepts are: - `strings`: log lines are `string` values. - `conditionals`: know how to execute conditional logic. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-enum]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md index b74806798d..0390c5adcc 100644 --- a/exercises/concept/flag-enums/.meta/design.md +++ b/exercises/concept/flag-enums/.meta/design.md @@ -18,8 +18,6 @@ As this is an advanced exercise, there are no enum-related things that we should ## Concepts -The Concepts this exercise unlocks are: - - `flag-enums`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. - `bit-manipulation`: know how to use bitwise operators to manipulate bits. diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index 23fe05671f..3f0cdad718 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -16,8 +16,6 @@ The goal of this exercise is to teach the student how the Concept of floating-po ## Concepts -The Concepts this exercise unlocks are: - - `floating-point-numbers`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. - `while-loops`: know how to write a `while` loop. @@ -28,14 +26,4 @@ This exercise's prerequisites Concepts are: - `numbers`: define numbers and apply arithmetic and boolean logic to them. - `conditionals`: conditionally execute code based on value of floating-point numbers. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index f09f3bb565..467968da68 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -18,24 +18,16 @@ The goal of this exercise is to teach the student the Concept of Inheritance in ## Concepts -This Concepts Exercise's Concepts are: - - `inheritance`: know what inheritance is; know how to inherit from a class; know that all types inherit from `object`; know what abstract and sealed classes are; know what abstract and virtual methods are; know how to override methods; know about the `protected` visibility modifier. ## Prequisites -This Concept Exercise's prerequisites Concepts are: - - `classes`: know how to work with classes. - `constructors`: know how to work with constructors. - `strings`: know how to do basic string interpolation. - `boolean`: know how to use boolean logic. - `conditionals`: know how to do conditional logic. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - ## Analyzer This exercise could benefit from the following rules added to the the [analyzer][analyzer]: @@ -44,4 +36,3 @@ This exercise could benefit from the following rules added to the the [analyzer] - Verify that the various fields used (hit points, spell prepared and potion drunk) use the `private` modifier. [analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/method-overloading/.meta/design.md index 6a2b5f6c07..9feba70738 100644 --- a/exercises/concept/method-overloading/.meta/design.md +++ b/exercises/concept/method-overloading/.meta/design.md @@ -16,16 +16,12 @@ The goal of this exercise is to teach the student the Concept of Method Overload ## Concepts -This Concepts Exercise's Concepts are: - - `method-overloading`: know what method overloading is; know how to define overloaded methods; know the limitations of method overloading - `optional-parameters`: know how to define optional parameters - `named-arguments`: know how to use named arguments ## Prequisites -This Concept Exercise's prerequisites Concepts are: - - `classes`: know how to define methods on classes - `constructors`: know how to define constructors on classes - `properties`: know how to work with properties @@ -33,10 +29,6 @@ This Concept Exercise's prerequisites Concepts are: - `strings`: know how to format strings - `basics`: know how to work with integers -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - ## Analyzer This exercise could benefit from the following rules added to the the [analyzer][analyzer]: @@ -44,4 +36,3 @@ This exercise could benefit from the following rules added to the the [analyzer] - Verify that the `Describe()` methods take take both a `Character` and `Destination` can be replaced with a single method that uses a default value for the `TravelMethod` parameter. [analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index ff3a94d4cf..b62b38e946 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -21,27 +21,13 @@ The goal of this exercise is to introduce the student to the concept of [Nullabi ## Concepts -This Concepts Exercise's Concepts are: - - `nullability`: know of the existence of the `null` literal; know what a `NullReferenceException` is and when it is thrown; know how to compare a value to `null`; know the difference between value and reference types regarding nullability; know how to define nullable reference and value types; know about the null-related operators; know about basic null checking by the compiler. ## Prerequisites -This Concept Exercise's prerequisites Concepts are: - - `strings`: strings will be compared to `null` and basic methods from strings will be called. - `basics`: integers will be compared to `null`, arithmetic operations will be performed on integers, variables will be introduced and updated. - `conditionals`: using a conditional statement. - `memory-allocation`: reference and value types will be used in their nullable and non-nullable variants. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index ca7a903ded..41c7efd79e 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -18,8 +18,6 @@ The goal of this exercise is to teach the student how the Concept of Numbers is ## Concepts -The Concepts this exercise unlocks are: - - `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to convert from one numeric type to another; know what implicit and explicit conversions are. - `conditionals`: know how to conditionally execute code using an `if` statement. @@ -29,14 +27,4 @@ This exercise's prerequisites Concepts are: - `basics`: know how to define methods. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index 7fb56bd413..1bf2a00a2d 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -26,8 +26,6 @@ Note that students may choose to implement expression-bodied members. ## Concepts -This Concepts Exercise's concepts are: - - `properties`: know what properties are and how they relate to fields and methods; know what backing-field properties are; know what auto-implemented properties are; know what calculated properties are; know how to use property accessors to customize visibility; know how to define the different types of properties. ## Prequisites diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index 936959d1e2..5db43afee4 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -17,8 +17,6 @@ The goal of this exercise is to teach the student the basics of the Concept of S ## Concepts -The Concepts this exercise unlocks are: - - `strings`: know of the existence of the `string` type; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string formatting. ## Prequisites @@ -27,14 +25,4 @@ This exercise's prerequisites Concepts are: - `basics`: know how to define methods. -## Representer - -This exercise does not require any specific representation logic to be added to the [representer][representer]. - -## Analyzer - -This exercise does not require any specific logic to be added to the [analyzer][analyzer]. - -[analyzer]: https://github.com/exercism/csharp-analyzer -[representer]: https://github.com/exercism/csharp-representer [docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 From 4f559fbe5adbbea9d93619a35575ae74700cff2e Mon Sep 17 00:00:00 2001 From: mirko Date: Tue, 2 Jun 2020 07:18:59 +0200 Subject: [PATCH 142/327] fix typo in basics exercise --- exercises/concept/basics/.docs/instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/basics/.docs/instructions.md index 1934d59e32..d761d505bb 100644 --- a/exercises/concept/basics/.docs/instructions.md +++ b/exercises/concept/basics/.docs/instructions.md @@ -1,6 +1,6 @@ In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book. -You have four tasks, all related to the time spent cooking the lasasgna. +You have four tasks, all related to the time spent cooking the lasagna. ## 1. Define the expected oven time in minutes From cb9351a2a114c80f208ef7513b3a3eaa8e9ccc9c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 2 Jun 2020 17:02:23 +0200 Subject: [PATCH 143/327] Remove goal from design.md * Remove goal from design docs * [F#] Remove goal from design docs * [Elixir] Remove goal from design docs --- exercises/concept/arrays/.meta/design.md | 4 ---- exercises/concept/basics/.meta/design.md | 4 ---- exercises/concept/booleans/.meta/design.md | 4 ---- exercises/concept/classes/.meta/design.md | 4 ---- exercises/concept/constructors/.meta/design.md | 4 ---- exercises/concept/datetimes/.meta/design.md | 4 ---- exercises/concept/dictionaries/.meta/design.md | 4 ---- exercises/concept/enums/.meta/design.md | 4 ---- exercises/concept/flag-enums/.meta/design.md | 4 ---- exercises/concept/floating-point-numbers/.meta/design.md | 4 ---- exercises/concept/inheritance/.meta/design.md | 4 ---- exercises/concept/method-overloading/.meta/design.md | 4 ---- exercises/concept/nullability/.meta/design.md | 4 ---- exercises/concept/numbers/.meta/design.md | 4 ---- exercises/concept/properties/.meta/design.md | 4 ---- exercises/concept/strings/.meta/design.md | 4 ---- 16 files changed, 64 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 5d94be436f..f755a7b35e 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Arrays in C#. - Of the many available C# collection types, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons: - Arrays don't require the student to know about generics. diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index aa0074da78..7102452fe9 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of programming in C#. - ## Learning objectives - Know what a variable is. diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/booleans/.meta/design.md index f79135b851..f2401cd437 100644 --- a/exercises/concept/booleans/.meta/design.md +++ b/exercises/concept/booleans/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Booleans in C#. - ## Learning objectives - Know of the existence of the `bool` type and its two values. diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index 86323fdb29..df42404c6b 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the Concept of Classes in C#. - ## Learning objectives - Know what classes are. diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md index 7e2083ba7a..2e63932043 100644 --- a/exercises/concept/constructors/.meta/design.md +++ b/exercises/concept/constructors/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the Concept of Constructors in C#. - ## Learning objectives - Know what constructors are diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/datetimes/.meta/design.md index e70fb32ad3..eee4a91147 100644 --- a/exercises/concept/datetimes/.meta/design.md +++ b/exercises/concept/datetimes/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Dates through [C#][docs.microsoft.com-datetime]. - ## Learning objectives - Know of the existence of the `DateTime` type. diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md index 8bfb4c7266..c8348a0371 100644 --- a/exercises/concept/dictionaries/.meta/design.md +++ b/exercises/concept/dictionaries/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Dictionaries in [C#][dictionaries-docs]. - ## Learning objectives - Know of the existence of the `Dictionary` type. diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index df456e5a11..a48667033d 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of enums through [C#][docs.microsoft.com-enum]. - ## Learning objectives After completing this exercise, the student should: diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md index 0390c5adcc..8e7b627327 100644 --- a/exercises/concept/flag-enums/.meta/design.md +++ b/exercises/concept/flag-enums/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student advanced aspects of the Concept of Enums in [C#][docs.microsoft.com-bitwise-and-shift-operators]. We'll do this in the form of working with [flag][docs.microsoft.com-flagsattribute] enums, which are enums whose values are interpreted as bitwise flags that can be manipulated through bitwise operations. - ## Learning objectives - Know what a flags enumeration is. diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index 3f0cdad718..71b098ce12 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student how the Concept of floating-point numbers is implemented in [C#][docs.microsoft.com-floating-point-numeric-types]. It will show the available floating-point types and discuss their differences. - ## Learning objectives - Know of the existence of the three floating point types: `double`, `float` and `decimal`. diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index 467968da68..0f479185fd 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the Concept of Inheritance in C#. - ## Learning objectives - Know what inheritance is. diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/method-overloading/.meta/design.md index 9feba70738..8387dea33f 100644 --- a/exercises/concept/method-overloading/.meta/design.md +++ b/exercises/concept/method-overloading/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the Concept of Method Overloading in C#. - ## Learning objectives - Know what method overloading is diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index b62b38e946..3a3ae4ef9d 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to introduce the student to the concept of [Nullability in C#][null-keyword]. - ## Learning objectives - Know of the existence of the `null` literal. diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index 41c7efd79e..2b83d28875 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student how the Concept of Numbers is implemented in [C#][docs.microsoft.com-numbers]. It will introduce this concept through the two most common numeric types in C#: `int` (whole number) and `double` (floating-point number). - ## Learning objectives - Know of the existence of the two most commonly used number types, `int` and `double`. diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index 1bf2a00a2d..093d1f6c88 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to introduce the student to C# properties and to teach the student how the concept of properties is implemented in [C#][docs.microsoft.com-properties]. We'll teach the student about properties by having the student work with classes that expose contrasting forms of properties. The students will learn to work with properties with backing fields and auto-implemented properties. - Properties are covered early in the C# track as their purpose and power can be shown with few dependencies (classes, access modifiers and fields of simple types). ## Learning objectives diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index 5db43afee4..41b63724ff 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -1,7 +1,3 @@ -## Goal - -The goal of this exercise is to teach the student the basics of the Concept of Strings in [C#][docs.microsoft.com-string]. - ## Learning objectives - Know of the existence of the `string` type. From 0c9ae8309f623cffd9ebf5dce33f41cdd0d9ea34 Mon Sep 17 00:00:00 2001 From: mirko Date: Tue, 9 Jun 2020 08:41:40 +0200 Subject: [PATCH 144/327] remove unused link ref --- exercises/concept/strings/.meta/design.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index 41b63724ff..8aba8b9d78 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -20,5 +20,3 @@ This exercise's prerequisites Concepts are: - `basics`: know how to define methods. - -[docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 From 0279182769c2a2deedf5966d192b5d5a4aa4086c Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 9 Jun 2020 07:42:09 +0100 Subject: [PATCH 145/327] Put concept out-of-scope --- reference/out-of-scope.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md index 99f2c3fcc8..09a06dd659 100644 --- a/reference/out-of-scope.md +++ b/reference/out-of-scope.md @@ -38,3 +38,5 @@ unless it is felt that the topic otherwise has insufficient prominence. - File handling - Networking - Compiler directives +- AssemblyInfo.cs + From 9b9023b86969db3bc88cc324f8b43a1b73f7f67d Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Tue, 9 Jun 2020 15:53:28 +0200 Subject: [PATCH 146/327] New concept exerise: `enum` Co-authored-by: Tim Austin --- reference/out-of-scope.md | 1 - 1 file changed, 1 deletion(-) diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md index 09a06dd659..f3adedd24e 100644 --- a/reference/out-of-scope.md +++ b/reference/out-of-scope.md @@ -39,4 +39,3 @@ unless it is felt that the topic otherwise has insufficient prominence. - Networking - Compiler directives - AssemblyInfo.cs - From 3d83bfc9005d7f44df1b525f4a4cc3d25588408a Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 11 Jun 2020 08:54:01 +0100 Subject: [PATCH 147/327] Add chars exercise * WIP * added tasks * tests complete * added initial draft of code * hints substantially complete * some work on after.md * extra tests * dictionaries - tweaked docs * dictionaries - formatting of code files * dictionaries - applied prettier * dictionaries - completing docs * dictionaries - completing docs * dictionaries - fixing github action issues * dictionaries - included proj file * dictionaries - proofed * dictionaries - proofed * dictionaries - proofed * dictionaries - added prereq * dictionaries - fixed typo * dictionaries - prettier * Update languages/exercises/concept/README.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/reference/README.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/introduction.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/DictionariesTest.cs Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/after.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/dictionaries/.docs/instructions.md Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * dictionaries - rounded out code review changes * Update languages/exercises/concept/dictionaries/.docs/introduction.md Co-authored-by: Erik Schierboom * dictionaries - prettying * dictionaries - prettying * dictionaries - prettying * chars upload directory layout * chars some content * chars much content * chars removed otiose using statement * chars corrected error in example code * chars after review * chars code files substantially complete * chars substantially complete * chars fixed review points * missed a review point on chars * chars fixed review points * chars fixed review points * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * chars fixed review points * chars prettier Co-authored-by: mikedamay Co-authored-by: Erik Schierboom --- exercises/concept/chars/.docs/after.md | 89 +++++++++++++++++++ exercises/concept/chars/.docs/hints.md | 29 ++++++ exercises/concept/chars/.docs/instructions.md | 43 +++++++++ exercises/concept/chars/.docs/introduction.md | 15 ++++ exercises/concept/chars/.meta/Example.cs | 40 +++++++++ exercises/concept/chars/.meta/config.json | 8 ++ exercises/concept/chars/.meta/design.md | 28 ++++++ exercises/concept/chars/Chars.cs | 9 ++ exercises/concept/chars/Chars.csproj | 13 +++ exercises/concept/chars/CharsTest.cs | 60 +++++++++++++ 10 files changed, 334 insertions(+) create mode 100644 exercises/concept/chars/.docs/after.md create mode 100644 exercises/concept/chars/.docs/hints.md create mode 100644 exercises/concept/chars/.docs/instructions.md create mode 100644 exercises/concept/chars/.docs/introduction.md create mode 100644 exercises/concept/chars/.meta/Example.cs create mode 100644 exercises/concept/chars/.meta/config.json create mode 100644 exercises/concept/chars/.meta/design.md create mode 100644 exercises/concept/chars/Chars.cs create mode 100644 exercises/concept/chars/Chars.csproj create mode 100644 exercises/concept/chars/CharsTest.cs diff --git a/exercises/concept/chars/.docs/after.md b/exercises/concept/chars/.docs/after.md new file mode 100644 index 0000000000..9a75061180 --- /dev/null +++ b/exercises/concept/chars/.docs/after.md @@ -0,0 +1,89 @@ +`char`s are generally easy to use. They can be extracted from strings, added back +(by means of a string builder), defined and initialised using literals with single quotes, as in `char ch = 'A';` +, assigned and compared. + +General information on `char`s can be found here: + +- [Chars documentation][chars-docs]: reference documentation for `char`. +- [Chars tutorial][chars-tutorial]: basic tutorial on how to work with chars. + +However, `char`s have a number of rough edges as detailed below. +These rough edges mostly relate to the opposition +between the full unicode standard on the one side and historic representations +of text as well as performance and memory usage on the other. + +### Unicode Issues + +When dealing with strings, if `System.String` library methods are available you should +seek these out and use them rather than breaking the string down into characters. +Some textual "characters" consist of more than one `char` because the unicode standard +has more than 65536 code points. For instance the emojis that show up in some +of the tests have 2 `char`s as they comprise [surrogate][surrogates] characters. +Additionally, there are combining sequences for instance where in some cases +an accented character may consist of one `char` for the plain character +and another `char` for the accent. + +If you have to deal with individual characters you should try to use +library methods such as [`System.Char.IsControl`][is-control], [`System.Char.IsDigit`][is-digit] +rather than making naive comparisons such as checking that a character is +between '0' and '9'. For instance, note that '٢' is the arabic digit 2. `IsDigit` +will return true for the arabic version so you need to be clear say when validating +what range of inputs is acceptable. Even the `System.Char` library methods may not +behave as you would expect when you are dealing with more obscure languages. + +One way safely to break a string into display "characters" is to use [`StringInfo`][string-info] and +methods such as [`GetNexttextElement`][get-next-text-element]. This might be necessary if you are +dealing with globalization/localization. Another avenue where the scalar values +of unicode characters is important (say you are rolling your own encoding system) is to use +[runes][runes]. However, if you know the range of characters +you deal with does not include surrogates or combining character sequences (e.g. Latin ASCII) and your input +is well validated then you can avoid this. Again, the best position to be in +is where you can use `String`'s library methods. + +If you do find yourself in the unenviable position of dealing with the minutiae of unicode +then [this][char-encoding-net] is a good starting point. + +### Globalization + +If you are working in an environment where you are dealing with multiple cultures or +the culture is important in some parts of the code but not others then be +aware of the overloads of [`ToUpper`][to-upper] and [`ToLower`][to-lower] which take a culture and +[`ToUpperInvariant`][to-upper-invariant] and [`ToLowerInvariant`][to-lower-invariant] which will provide a consistent +result irrespective of the current [culture][culture-info]. + +### Representation, Characters and Integers + +Like other simple types (`int`s, `bool`s, etc.) the `char` has a companion +or alias type, in this case, `System.Char`. This is in fact a `struct` with +a 16 bit field. `char` in fact has some instance methods such as +`Equals`, `ToString` and [`CompareTo`][compare-to]. + +`char` has the same width as a [`ushort`][uint16] but they are generally +not used inter-changeably as they are in some languages. `ushort` has +to be explicitly cast to a `char`. For what it's worth `char`s can +be subject to arithmetic operations. The result of these operations is an integer. + +Obviously there is no equivalence between a `byte` at 8 bits and the 16 bit `char`. + +### Performance + +Using `StringBuilder` is seen as hugely preferable to building up strings with multiple repeated concatenations with +a `+` or `+=` operator. Obviously simple one off concatenations are preferable +to instantiating a `StringBuilder` for clarity as well as performance. + +[chars-docs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char +[chars-tutorial]: https://csharp.net-tutorials.com/data-types/the-char-type/ +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 +[uint16]: https://docs.microsoft.com/en-us/dotnet/api/system.uint16?view=netcore-3.1 +[string-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo?view=netcore-3.1 +[runes]: https://docs.microsoft.com/en-us/dotnet/api/system.text.rune?view=netcore-3.1 +[char-encoding-net]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding-introduction +[surrogates]: https://docs.microsoft.com/en-us/dotnet/api/system.char.issurrogate?view=netcore-3.1 +[is-control]: https://docs.microsoft.com/en-us/dotnet/api/system.char.iscontrol?view=netcore-3.1 +[to-upper]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupper?view=netcore-3.1#System_Char_ToUpper_System_Char_System_Globalization_CultureInfo_ +[to-lower]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolower?view=netcore-3.1#System_Char_ToLower_System_Char_System_Globalization_CultureInfo_ +[to-upper-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupperinvariant?view=netcore-3.1 +[to-lower-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolowerinvariant?view=netcore-3.1 +[is-digit]: https://docs.microsoft.com/en-us/dotnet/api/system.char.isdigit?view=netcore-3.1 +[get-next-text-element]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo.getnexttextelement?view=netcore-3.1 +[compare-to]: https://docs.microsoft.com/en-us/dotnet/api/system.char.compareto?view=netcore-3.1 diff --git a/exercises/concept/chars/.docs/hints.md b/exercises/concept/chars/.docs/hints.md new file mode 100644 index 0000000000..2610b7b655 --- /dev/null +++ b/exercises/concept/chars/.docs/hints.md @@ -0,0 +1,29 @@ +### 1. Replace any spaces encountered with underscores + +- [This tutorial][chars-tutorial] is useful. +- [Reference documentation][chars-docs] for `char`s is here. +- You can retrieve `char`s from a string in the same way as elements from an array. +- You should use a [`StringBuilder`][string-builder] to build the output string. +- See [this method][iswhitespace] for detecting spaces. Remember it is a static method. +- `char` literals are enclosed in single quotes. + +### 2. Replace control characters with the upper case string "CTRL" + +- See [this method][iscontrol] to check if a character is a control character. + +### 3. Convert kebab-case to camel-case + +- See [this method][toupper] to convert a character to upper case. + +### 4. Omit Greek lower case letters + +- `char`s support the default equality and comparison operators. + +[chars-docs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char +[chars-tutorial]: https://csharp.net-tutorials.com/data-types/the-char-type/ +[string-builder]: https://docs.microsoft.com/en-us/dotnet/api/system.text.stringbuilder?view=netcore-3.1 +[iswhitespace]: https://docs.microsoft.com/en-us/dotnet/api/system.char.iswhitespace?view=netcore-3.1#System_Char_IsWhiteSpace_System_Char_ +[iscontrol]: https://docs.microsoft.com/en-us/dotnet/api/system.char.iscontrol?view=netcore-3.1 +[toupper]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupper?view=netcore-3.1 +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators +[comparison]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators diff --git a/exercises/concept/chars/.docs/instructions.md b/exercises/concept/chars/.docs/instructions.md new file mode 100644 index 0000000000..83085ef9c3 --- /dev/null +++ b/exercises/concept/chars/.docs/instructions.md @@ -0,0 +1,43 @@ +In this exercise you will implement a partial set of utility routines to help a developer +clean up identifier names. + +In the 4 tasks you will gradually build up the routine `Clean` A valid identifier comprises +zero or more letters and underscores. + +In all cases the input string is guaranteed to be non-null. Note that the `Clean` method should treat an empty string as valid. + +### 1. Replace any spaces encountered with underscores + +Implement the (_static_) `Identifier.Clean()` method to replace any spaces with underscores. This also applies to leading and trailing spaces. + +```csharp +Identifier.Clean("my Id"); +// => "my___Id" +``` + +### 2. Replace control characters with the upper case string "CTRL" + +Modify the (_static_) `Identifier.Clean()` method to replace control characters with the upper case string `"CTRL"`. + +```csharp +Identifier.Clean("my\0Id"); +// => "myCTRLId", +``` + +### 3. Convert kebab-case to camelCase + +Modify the (_static_) `Identifier.Clean()` method to convert kebab-case to camelCase. + +```csharp +Identifier.Clean("à-ḃç"); +// => "àḂç" +``` + +### 4. Omit Greek lower case letters + +Modify the (_static_) `Identifier.Clean()` method to omit any Greek letters in the range 'α' to 'ω'. + +```csharp +Identifier.Clean("MyΟβιεγτFinder"); +// => "MyΟFinder" +``` diff --git a/exercises/concept/chars/.docs/introduction.md b/exercises/concept/chars/.docs/introduction.md new file mode 100644 index 0000000000..c081632203 --- /dev/null +++ b/exercises/concept/chars/.docs/introduction.md @@ -0,0 +1,15 @@ +The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text. +Multiple `char`s can comprise a string such as `"word"` or `char`s can be +processed independently. Their literals have single quotes e.g. `'A'`. + +C# `char`s support UTF-16 Unicode encoding so in addition to the latin character set +pretty much all the writing systems in use world can be represented, +e.g. ancient greek `'β'`. + +There are many builtin library methods to inspect and manipulate `char`s. These +can be found as static methods of the `System.Char` class. + +`char`s are sometimes used in conjunction with a `StringBuilder` object. +This object has methods that allow a string to be constructed +character by character and manipulated. At the end of the process +`ToString` can be called on it to output a complete string. diff --git a/exercises/concept/chars/.meta/Example.cs b/exercises/concept/chars/.meta/Example.cs new file mode 100644 index 0000000000..a738868836 --- /dev/null +++ b/exercises/concept/chars/.meta/Example.cs @@ -0,0 +1,40 @@ +using System; +using System.Text; + +public static class Identifier +{ + public static string Clean(string identifier) + { + var UNDERSCORE = '_'; + var DASH = '-'; + var ALPHA = 'α'; + var OMEGA = 'ω'; + var sb = new StringBuilder(); + for (int i = 0; i < identifier.Length; i++) + { + char ch = identifier[i]; + if (Char.IsWhiteSpace(ch)) + { + sb.Append(UNDERSCORE); + } + else if (Char.IsControl(ch)) + { + sb.Append("CTRL"); + } + else if (ch == DASH) + { + if (i + 1 < identifier.Length) + { + sb.Append(Char.ToUpper(identifier[i + 1])); + i++; + } + } + else if (Char.IsLetter(ch) && (ch < ALPHA || ch > OMEGA) || ch == UNDERSCORE) + { + sb.Append(ch); + } + } + + return sb.ToString(); + } +} diff --git a/exercises/concept/chars/.meta/config.json b/exercises/concept/chars/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/chars/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/chars/.meta/design.md b/exercises/concept/chars/.meta/design.md new file mode 100644 index 0000000000..77e020d13f --- /dev/null +++ b/exercises/concept/chars/.meta/design.md @@ -0,0 +1,28 @@ +## Learning objectives + +- Know of the existence of the `char` type. +- Know what a char represents (a Unicode character). +- Know how to define a `char`. +- Know that a `char` is not the same as a single character string +- Know how to access a `char` in a string by index. +- Know of some basic `char` methods (like converting to uppercase). +- Know that `char`s are immutable. +- Know how to compare characters +- Know how to use a `StringBuilder` + +## Out of scope + +- Converting an integer to a character and vice versa. +- `System.Char` as a struct - alias for the simple `char` type +- Advanced unicode issues such as surrogates, text normalization, combining characters +- cultural considerations and invariants + +## Concepts + +- `chars`: know of the existence of the `char` type; know that a `char` represents; know how to define a `char`; know how to access a `char` in a string by index; know of some basic `char` methods (like converting to uppercase). +- `StringBuilder`: know how to use this. + +## Prequisites + +- `strings`: know of the `string` type that will be iterated over and accessed by index. +- `for-loop` for loops (rather than foreach) are the best means of highlighting the relationship between strings and `char`s diff --git a/exercises/concept/chars/Chars.cs b/exercises/concept/chars/Chars.cs new file mode 100644 index 0000000000..42ad2d51aa --- /dev/null +++ b/exercises/concept/chars/Chars.cs @@ -0,0 +1,9 @@ +using System; + +public static class Identifier +{ + public static string Clean(string identifier) + { + throw new NotImplementedException($"Please implement the (static) Identifier.Clean() method"); + } +} diff --git a/exercises/concept/chars/Chars.csproj b/exercises/concept/chars/Chars.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/chars/Chars.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/chars/CharsTest.cs b/exercises/concept/chars/CharsTest.cs new file mode 100644 index 0000000000..d30f44f9a5 --- /dev/null +++ b/exercises/concept/chars/CharsTest.cs @@ -0,0 +1,60 @@ +using Xunit; + +public class CharsTest +{ + [Fact] + public void Clean_empty_string() + { + Assert.Equal(string.Empty, Identifier.Clean(string.Empty)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_single_letter() + { + Assert.Equal("A", Identifier.Clean("A")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_clean_string() + { + Assert.Equal("àḃç", Identifier.Clean("àḃç")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_string_with_spaces() + { + Assert.Equal("my___Id", Identifier.Clean("my Id")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_string_with_control_char() + { + Assert.Equal("myCTRLId", Identifier.Clean("my\0Id")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_string_with_no_letters() + { + Assert.Equal(string.Empty, Identifier.Clean("😀😀😀")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Convert_kebab_to_camel_case() + { + Assert.Equal("àḂç", Identifier.Clean("à-ḃç")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Omit_lower_case_greek_letters() + { + Assert.Equal("MyΟFinder", Identifier.Clean("MyΟβιεγτFinder")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Combine_conversions() + { + Assert.Equal("_AbcĐCTRL", Identifier.Clean("9 -abcĐ😀ω\0")); + } + + +} From 9b6e0fb7dfe32ad530d0b69e69ee52593d1edec7 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 11 Jun 2020 12:10:07 +0100 Subject: [PATCH 148/327] inheritance elaborate on sealed classes * inheritance elaborate on sealed classes * Update languages/exercises/concept/inheritance/.docs/after.md Co-authored-by: Erik Schierboom Co-authored-by: Erik Schierboom --- exercises/concept/inheritance/.docs/after.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/exercises/concept/inheritance/.docs/after.md b/exercises/concept/inheritance/.docs/after.md index 90a7a0fd83..7ba8e9ef9c 100644 --- a/exercises/concept/inheritance/.docs/after.md +++ b/exercises/concept/inheritance/.docs/after.md @@ -1,4 +1,4 @@ -In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. To prevent a class being inherited, add the [`sealed` modifier][sealed-classes]. +In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. Parent classes can provide functionality to derived classes in three ways: @@ -61,6 +61,9 @@ class Car : Vehicle } ``` +To prevent a class being inherited, add the [`sealed` modifier][sealed-classes]. +Some practitioners try to avoid inheriting from concrete classes (as discussed in [this SO question][pro-sealed]) and the _sealed_ modifier supports this approach. On the other hand many C# developers consider them a hindrance to maintenance as discussed in some of the comments on [this question][anti-sealed]. The advice is to use the sealed modifier sparingly until you have gained confidence in their use for your requirements. + [abstract-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract [virtual-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual [override-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override @@ -71,3 +74,5 @@ class Car : Vehicle [constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors [abstract-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#abstract-classes-and-class-members [sealed-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members +[pro-sealed]: https://stackoverflow.com/questions/16724946/why-derive-from-a-concrete-class-is-a-poor-design +[anti-sealed]: https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class From 7ee12cd8a460328aff921692726041800db31c38 Mon Sep 17 00:00:00 2001 From: Angelika Tyborska Date: Mon, 15 Jun 2020 08:29:59 +0200 Subject: [PATCH 149/327] Remove duplicate datetime format from the appointment scheduler story --- exercises/concept/datetimes/.docs/instructions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exercises/concept/datetimes/.docs/instructions.md b/exercises/concept/datetimes/.docs/instructions.md index bfa03caf42..929d126754 100644 --- a/exercises/concept/datetimes/.docs/instructions.md +++ b/exercises/concept/datetimes/.docs/instructions.md @@ -1,11 +1,10 @@ In this exercise you'll be working on an appointment scheduler for a beauty salon in New York that opened on September 15th in 2012. -You have four tasks, which will all involve appointment dates. The dates and times will use one of the following four formats: +You have four tasks, which will all involve appointment dates. The dates and times will use one of the following three formats: - `"7/25/2019 13:45:00"` - `"July 25, 2019 13:45:00"` - `"Thursday, July 25, 2019 13:45:00:00"` -- `"July 25, 2019 13:45:00"` The tests will automatically set the culture to `en-US` - you don't have to set or specify the culture yourselves. From 546febe829daaaeb18ccc841ee81d3d7f8e135b7 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 16 Jun 2020 09:53:58 +0100 Subject: [PATCH 150/327] added pre-requisite --- exercises/concept/dictionaries/.meta/design.md | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md index c8348a0371..b3157c7ccf 100644 --- a/exercises/concept/dictionaries/.meta/design.md +++ b/exercises/concept/dictionaries/.meta/design.md @@ -28,6 +28,7 @@ - `generic-types`: know how generic types work. - `strings`: know how to discover string length - `indexers`: usage and behavior of indexer properties +- `object-initializers`: how object initializers are used with collections. [how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/master/docs/maintainers/generic-how-to-implement-a-concept-exercise.md [implemented-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md#implemented-exercises From 06e2ed6db560d9ca672285d0d472b71c182f3da9 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 16 Jun 2020 10:58:22 +0200 Subject: [PATCH 151/327] Fix test name filenames Fix naming of test file for chars exercise Fix naming of test file for dictionaries exercise --- exercises/concept/chars/{CharsTest.cs => CharsTests.cs} | 0 .../dictionaries/{DictionariesTest.cs => DictionariesTests.cs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename exercises/concept/chars/{CharsTest.cs => CharsTests.cs} (100%) rename exercises/concept/dictionaries/{DictionariesTest.cs => DictionariesTests.cs} (100%) diff --git a/exercises/concept/chars/CharsTest.cs b/exercises/concept/chars/CharsTests.cs similarity index 100% rename from exercises/concept/chars/CharsTest.cs rename to exercises/concept/chars/CharsTests.cs diff --git a/exercises/concept/dictionaries/DictionariesTest.cs b/exercises/concept/dictionaries/DictionariesTests.cs similarity index 100% rename from exercises/concept/dictionaries/DictionariesTest.cs rename to exercises/concept/dictionaries/DictionariesTests.cs From 9d628d26c977ff395c4933452b43ddd2c13339a5 Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 17 Jun 2020 12:57:03 +0100 Subject: [PATCH 152/327] Add exercise User-defined Exceptions * user-exceptions initial upload * user-exceptions initial code/instructions complete * user-exceptions tweak to design.md * user-exceptions proofing * user-exceptions proofing * user-exceptions after review * user-exceptions after review * user-exceptions intro and after * user-exceptions tweaking docs * Update languages/exercises/concept/user-defined-exceptions/.meta/Example.cs Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * user-exceptions more review changes * user-exceptions substantially complete * user-exceptions removed text not required for publication * user-exceptions added pre-requisites * user-exceptions updated out-of-date instructions * user-exceptions updated config * Apply suggestions from code review Co-authored-by: Erik Schierboom * Update languages/exercises/concept/user-defined-exceptions/.docs/after.md Co-authored-by: Erik Schierboom * user-exceptions late review points * Update after.md * copy/paste error Co-authored-by: Erik Schierboom --- .../user-defined-exceptions/.docs/after.md | 50 ++++++++++++++ .../user-defined-exceptions/.docs/hints.md | 22 ++++++ .../.docs/instructions.md | 56 ++++++++++++++++ .../.docs/introduction.md | 23 +++++++ .../user-defined-exceptions/.meta/Example.cs | 67 +++++++++++++++++++ .../user-defined-exceptions/.meta/config.json | 9 +++ .../user-defined-exceptions/.meta/design.md | 27 ++++++++ .../UserDefinedExceptions.csproj | 13 ++++ .../UserDefinedExceptionsTests.cs | 36 ++++++++++ .../UserDefinedExceptons.cs | 47 +++++++++++++ 10 files changed, 350 insertions(+) create mode 100644 exercises/concept/user-defined-exceptions/.docs/after.md create mode 100644 exercises/concept/user-defined-exceptions/.docs/hints.md create mode 100644 exercises/concept/user-defined-exceptions/.docs/instructions.md create mode 100644 exercises/concept/user-defined-exceptions/.docs/introduction.md create mode 100644 exercises/concept/user-defined-exceptions/.meta/Example.cs create mode 100644 exercises/concept/user-defined-exceptions/.meta/config.json create mode 100644 exercises/concept/user-defined-exceptions/.meta/design.md create mode 100644 exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj create mode 100644 exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs create mode 100644 exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs diff --git a/exercises/concept/user-defined-exceptions/.docs/after.md b/exercises/concept/user-defined-exceptions/.docs/after.md new file mode 100644 index 0000000000..841351f175 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.docs/after.md @@ -0,0 +1,50 @@ +A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. User-defined exceptions can be used in every way like runtime and Microsoft Base Class Library exceptions. + +This special treatment applies only to `Exception`-derived classes. You cannot throw instances of any other type. + +User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines. This can then be recorded in logs, reported to a user or perhaps used in a retry operation. `System.Exception` has convenient data members and appropriate constructors to hold a message and the "inner" exception. + +By convention exception class names end with "Exception", e.g. `MyTerribleException`. + +Whilst using user-defined exceptions to wrap and enhance third party exceptions is a frequently seen pattern, the general advice is not to use them outside of this use case too liberally in your own code. It is considered an anti-pattern. There are challenges to this view and you can see both sides of the argument in this [Stack Exchange post][se-exceptions]. + +This [article][create-user-defined-exceptions] is a good introduction to user-defined exceptions. + +As part of their guidance on [creating and throwing exceptions][exceptions-guidance] the .NET team recommend that user defined exceptions have a number of [convenience constructors][convenience-constructors]. For most purposes the combination illustrated below is appropriate. + +```csharp +public class IncompleteExerciseException : System.Exception +{ + public IncompleteExerciseException() : base() { } + public IncompleteExerciseException(string message) : base(message) { } + public IncompleteExerciseException(string message, System.Exception inner) : base(message, inner) { } +} +``` + +## Exception Filters + +`when` is the keyword in filtering exceptions. It is placed after the catch +statement and can take a boolean expression containing any values in scope at the time. They don't just have to be members of the exception itself. If the type of the exception matches and the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked. + +```csharp +try +{ + // do stuff +} +catch (Exception ex) when (ex.Message != "") +{ + // output the message when it is not empty +} +catch (Exception ex) +{ + // show stack trace or something. +} +``` + +- This [Exception filters][exception-filters] article shows how to filter exceptions. + +[create-user-defined-exceptions]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions +[exception-filters]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/when +[se-exceptions]: https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why +[exceptions-guidance]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions +[convenience-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions#defining-exception-classes diff --git a/exercises/concept/user-defined-exceptions/.docs/hints.md b/exercises/concept/user-defined-exceptions/.docs/hints.md new file mode 100644 index 0000000000..47da3a1127 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.docs/hints.md @@ -0,0 +1,22 @@ +## General + +- [Create user-defined exceptions][create-user-defined-exceptions]: how to create user-defined exceptions +- [Exception filters][exception-filters]: how to filter user-defined-exceptions. + +## 1. Complete the definition of the user-defined exception `CalculationException` + +- The constructors of the `Exception` base class are discussed [here][exception-constructors]. + +## 2. Implement the `Multiply()` method + +- `try-catch` blocks are discussed [here][try-catch] as well as in the `exceptions` exercise. + +## 4. Implement the `TestMultiplication()` method + +- This [article][try-catch-when] has an example of the use of `when`. + +[create-user-defined-exceptions]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions +[exception-filters]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/when +[exception-constructors]: https://docs.microsoft.com/en-us/dotnet/api/system.exception.-ctor?view=netcore-3.1 +[try-catch]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-the-try-catch-block-to-catch-exceptions +[try-catch-when]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch diff --git a/exercises/concept/user-defined-exceptions/.docs/instructions.md b/exercises/concept/user-defined-exceptions/.docs/instructions.md new file mode 100644 index 0000000000..efd11c69ff --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.docs/instructions.md @@ -0,0 +1,56 @@ +While working at _Instruments of Texas_, you are tasked to work on an experimental calculator written in C#. You are building a test harness to verify a number of calculator functions starting with multiplication. You will see that there is particular concern when the two operands of the multiplication are negative. + +The `Calculator` class has been provided for you and should not be modified. + +## 1. Complete the definition of the user-defined exception `CalculationException` + +Complete the definition of the constructor of `CalculationException` which will need to store (wrap) any exception thrown by the calculator as well as the operands that are being processed at the time the exception is thrown. + +## 2. Handle overflow conditions in the calculator and provide enhanced information to the caller + +Implement the `CalculatorTestHarness.Multiply()` method, which should call the `Calculator.Multiply()` method of the `Calculator` instance passed to the constructor. +passing in x and y integer values. If an overflow occurs in the `Calculator.Multiply()` method, it will throw an `OverflowException`. This exception should be caught in the `CalculatorTestHarness.Multiply()` method and wrapped in a `CalculationException` and the x and y values being passed around should be stored as the exception's operands. The newly created `CalculationException` object should be thrown. You can ignore the value returned by the `Calculator.Multiply()` method if it is successful. + +```csharp +var cth = new CalculatorTestHarness(new Calculator()); +cth.Multiply(Int32.MaxValue, Int32.MaxValue); +// => throws an instance of CalculationException + +var cth2 = new CalculatorTestHarness(new Calculator()); +cth2.Multiply(3, 2); +// => silently exits +``` + +## 3. Test the multiplication operation for valid inputs + +Implement the `CalculatorTestHarness.TestMultiplication()` method which takes two integers and calls the `CalculatorTestHarness.Multiply()` method. `"Multiply succeeded"` is returned. + +```csharp +var cth = new CalculatorTestHarness(new Calculator()); +cth.Multiply(6, 7); +// => "Multiply succeeded" +``` + +## 4. Test the multiplication operation for negative inputs + +Modify the `CalculatorTestHarness.TestMultiplication()` method so that `"Multiply failed for negative operands. "`is returned if both integer arguments are negative (less than zero). + +The `` placeholder should be replaced with the `CalculationException`'s inner exception's message. + +```csharp +var cth = new CalculatorTestHarness(new Calculator()); +cth.TestMultiplication(-2, -Int32.MaxValue); +// => "Multiply failed for negative operands. " + innerException.Message +``` + +## 5. Test the multiplication operation for positive inputs + +Modify the `CalculatorTestHarness.TestMultiplication()` method so that `"Multiply failed for mixed or positive operands. "` is returned if at least one of the integer arguments is not negative. + +The `` placeholder should be replaced with the `CalculationException`'s inner exception's message. + +```csharp +var cth = new CalculatorTestHarness(new Calculator()); +cth.TestMultiplication(Int32.MaxValue, Int32.MaxValue); +// => "Multiply failed for mixed or positive operands. " + innerException.Message +``` diff --git a/exercises/concept/user-defined-exceptions/.docs/introduction.md b/exercises/concept/user-defined-exceptions/.docs/introduction.md new file mode 100644 index 0000000000..9d60e65960 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.docs/introduction.md @@ -0,0 +1,23 @@ +A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. + +User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines. + +## Exception Filters + +`when` is the key word in filtering exceptions. It is placed after the catch +statement and can take a boolean expression containing any values in scope at the time. If the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked. + +```csharp +try +{ + // do stuff +} +catch (Exception ex) when (ex.Message != "") +{ + // output the message when it is not empty +} +catch (Exception ex) +{ + // show stack trace or something. +} +``` diff --git a/exercises/concept/user-defined-exceptions/.meta/Example.cs b/exercises/concept/user-defined-exceptions/.meta/Example.cs new file mode 100644 index 0000000000..9d8a76d1e9 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.meta/Example.cs @@ -0,0 +1,67 @@ +using System; + +public class CalculationException : Exception +{ + public CalculationException(int operand1, int operand2, string message, Exception inner) : base(message, inner) + { + Operand1 = operand1; + Operand2 = operand2; + } + + public int Operand1 { get; } + public int Operand2 { get; } +} + +public class CalculatorTestHarness +{ + private Calculator calculator; + + public CalculatorTestHarness(Calculator calculator) + { + this.calculator = calculator; + } + + public string TestMultiplication(int x, int y) + { + try + { + Multiply(x, y); + return "Multiply succeeded"; + } + catch (CalculationException cex) when (cex.Operand1 < 0 && cex.Operand2 < 0) + { + return "Multiply failed for negative operands. " + cex.InnerException.Message; + } + catch (CalculationException cex) + { + return "Multiply failed for mixed or positive operands. " + cex.InnerException.Message; + } + } + + public void Multiply(int x, int y) + { + try + { + calculator.Multiply(x, y); + } + catch (OverflowException ofex) + { + throw new CalculationException(x, y, string.Empty, ofex); + } + } +} + + +// Please do not modify the code below. +// If there is an overflow in the multiplication operation +// then a System.OverflowException is thrown. +public class Calculator +{ + public int Multiply(int x, int y) + { + checked + { + return x * y; + } + } +} diff --git a/exercises/concept/user-defined-exceptions/.meta/config.json b/exercises/concept/user-defined-exceptions/.meta/config.json new file mode 100644 index 0000000000..3865ea9589 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.meta/config.json @@ -0,0 +1,9 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "forked_from": ["elixir/errors"] +} diff --git a/exercises/concept/user-defined-exceptions/.meta/design.md b/exercises/concept/user-defined-exceptions/.meta/design.md new file mode 100644 index 0000000000..374a5e39cc --- /dev/null +++ b/exercises/concept/user-defined-exceptions/.meta/design.md @@ -0,0 +1,27 @@ +## Learning objectives + +- Know how to define a user-defined exception. +- Know how to use exception filtering. +- Know that using errors as control logic is an anti-pattern + +## Out of scope + +- Memory and performance characteristics. + +## Concepts + +This Concepts Exercise's Concepts are: + +- `user-defined-exceptions`: know how to define a user-defined exception. +- `exception-filtering`: know how to use exception filtering. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `exceptions`: know how to work with exceptions. +- `inheritance`: inheriting from the `Exception` class for the custom exception. +- `strings`: converting an into a string +- `conditionals`: use of simple `if`/`else` +- `arithmetic-overflow` +- `signed-integers`: `Int32.MaxValue` diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj b/exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs b/exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs new file mode 100644 index 0000000000..7ee12a9ab3 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs @@ -0,0 +1,36 @@ +using System; +using Xunit; + +public class UserDefinedExceptionsTests +{ + [Fact] + public void Multiply_with_overflow_throws_calculationexception() + { + var cth = new CalculatorTestHarness(new Calculator()); + + Assert.Throws(() => cth.Multiply(Int32.MaxValue, Int32.MaxValue)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TestMultiplication_with_negative_overflow() + { + var cth = new CalculatorTestHarness(new Calculator()); + Assert.Equal("Multiply failed for negative operands. Arithmetic operation resulted in an overflow.", + cth.TestMultiplication(-2, -Int32.MaxValue)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void TestMultiplication_with_positive_overflow() + { + var cth = new CalculatorTestHarness(new Calculator()); + Assert.Equal("Multiply failed for mixed or positive operands. Arithmetic operation resulted in an overflow.", + cth.TestMultiplication(Int32.MaxValue, Int32.MaxValue)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Call_TestMultiplication_with_success() + { + var cth = new CalculatorTestHarness(new Calculator()); + Assert.Equal("Multiply succeeded", cth.TestMultiplication(6, 7)); + } +} diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs b/exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs new file mode 100644 index 0000000000..9b39876ba3 --- /dev/null +++ b/exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs @@ -0,0 +1,47 @@ +using System; + +public class CalculationException : Exception +{ + public CalculationException(int operand1, int operand2, string message, Exception inner) + // TODO: complete the definition of the constructor + { + } + + public int Operand1 { get; } + public int Operand2 { get; } +} + +public class CalculatorTestHarness +{ + private Calculator calculator; + + public CalculatorTestHarness(Calculator calculator) + { + this.calculator = calculator; + } + + public string TestMultiplication(int x, int y) + { + throw new NotImplementedException("Please implement the CalculatorTestHarness.TestMultiplication() method"); + } + + public void Multiply(int x, int y) + { + throw new NotImplementedException("Please implement the CalculatorTestHarness.Multiply() method"); + } +} + + +// Please do not modify the code below. +// If there is an overflow in the multiplication operation +// then a System.OverflowException is thrown. +public class Calculator +{ + public int Multiply(int x, int y) + { + checked + { + return x * y; + } + } +} From f8b7748e6724153d1efac0ebc5412c69d5111a1d Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 24 Jun 2020 15:02:14 +0100 Subject: [PATCH 153/327] Implement Tuples Exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom Co-authored-by: Erik Schierboom --- exercises/concept/tuples/.docs/after.md | 155 ++++++++++++++++++ exercises/concept/tuples/.docs/hints.md | 15 ++ .../concept/tuples/.docs/instructions.md | 30 ++++ .../concept/tuples/.docs/introduction.md | 51 ++++++ exercises/concept/tuples/.meta/Example.cs | 14 ++ exercises/concept/tuples/.meta/config.json | 8 + exercises/concept/tuples/.meta/design.md | 24 +++ exercises/concept/tuples/Tuples.cs | 14 ++ exercises/concept/tuples/Tuples.csproj | 13 ++ exercises/concept/tuples/TuplesTest.cs | 46 ++++++ 10 files changed, 370 insertions(+) create mode 100644 exercises/concept/tuples/.docs/after.md create mode 100644 exercises/concept/tuples/.docs/hints.md create mode 100644 exercises/concept/tuples/.docs/instructions.md create mode 100644 exercises/concept/tuples/.docs/introduction.md create mode 100644 exercises/concept/tuples/.meta/Example.cs create mode 100644 exercises/concept/tuples/.meta/config.json create mode 100644 exercises/concept/tuples/.meta/design.md create mode 100644 exercises/concept/tuples/Tuples.cs create mode 100644 exercises/concept/tuples/Tuples.csproj create mode 100644 exercises/concept/tuples/TuplesTest.cs diff --git a/exercises/concept/tuples/.docs/after.md b/exercises/concept/tuples/.docs/after.md new file mode 100644 index 0000000000..6b989c403d --- /dev/null +++ b/exercises/concept/tuples/.docs/after.md @@ -0,0 +1,155 @@ +In C#, a tuple is a data structure which organizes data, holding two or more fields +of any type. + +A tuple is typically created by placing 2 or more expressions separated by comas, +within a set of parentheses. + +```csharp +string boast = "All you need to know"; +bool success = !string.IsNullOrWhiteSpace(boast); +(bool, int, string) tripple = (success, 42, boast); +``` + +As an expression like any other, a tuple can be used in a range of ways: in [assignments][tuple-assignment], +to initialize a field or variable, [return value][tuple-return-values] from a method or passed as a parameter. +They can be tested for [equality][tuple-equality]. Equality of tuples is illustrated fully in the `pattern-matching-tuples` exercise but an example is provided in the code below for the sake of completeness. + +Fields are extracted using dot syntax. By default, the first field is `Item1`, +the second `Item2`, etc. Non-default names are discussed below under _Naming_. + +A tuple can be used as a generic parameter, e.g. `IList<(bool, string)>` + +In addition, tuples support "deconstruction", discussed below +, and can be used in pattern matching which is covered in a later exercise. + +```csharp +// initialization +(int, int, int) vertices = (90, 45, 45); + +// assignment +vertices = (60, 60, 60); + +// return value +(bool, int) GetSameOrBigger(int num1, int num2) +{ + return (num1 == num2, num1 > num2 ? num1 : num2); +} + +// method argument +int Add((int, int) operands) +{ + return operands.Item1 + operands.Item2; +} + +// equality testing +var estimateA = (42, 1729); +var estimateB = (2*3*7, 7*13*19); +bool result = estimateA == estimateB; +// => result == true +``` + +This [introduction][tuples] shows how to define and use tuples. + +### Naming + +Field names `Item1` etc. do not make for readable code. There are 3 ways to +provide names to the fields a) in the type declaration or b) in the expression that +creates it, c) by means of [tuple projection initializers][tuple-projection-initializers] +(not illustrated here). + +```csharp +// name items in declaration +(bool success, string message) results = (true, "well done!"); +bool mySuccess = results.success; +string myMessaage = results.message; + +// name items in creating expression +var results2 = (success: true, message: "well done!"); +bool mySuccess2 = results2.success; +string myMessaage2 = results2.message; +``` + +Don't try to be too clever with the naming mechanism. It is really just syntactic +sugar. For example, you cannot change the names of a tuple when you assign to it +from another tuple. + +### Deconstruction + +Sometimes it is convenient to take a tuple and assign the fields to multiple variables +and initialize them if appropriate. +This mechanism is called [deconstruction][tuple-deconstruction]. (It can also +be applied to your own objects. See [here][udt-deconstruction]). + +```csharp +var goodNumbers = (42, 3.142, 1729); +(int ultimateQuestion, var π, var ramanujan) = goodNumbers; +return ultimateQuestion; +// => 42 +``` + +### Field Assignment + +The fields of tuples can be individually assigned to. +However, given the trend in C# towards immutability this +sort of usage is not widespread. Tuples are often used as if they were immutable +which of course they are not. + +```csharp +(int, string) tpl; +tpl.Item1 = 1; +tpl.Item2 = "bad"; +tpl.Item2 = "even worse"; +// => (1, "even worse"; +``` + +### Background + +The tuples we are discussing should not be confused with [`System.Tuple`][system-tuple] +which will probably be found only in legacy code bases. + +The position is slightly more confusing when it comes to `System.ValueTuple`. +The [docs][system-value-tuple] for the final overload of [`System.ValueTuple`][system-value-tuple]state that +"The value tuple types provide the runtime implementation that supports tuples in C# ". +By "value tuple types" here they are referring to the generic overloads of `System.ValueTuple`. +By "tuples" they mean the things that have concerned us in this exercise. +Effectively they are saying that `System.ValueTuple` is an implementation detail of tuples. This is +unlikely to be of much interest, most of the time, to most people. Unfortunately much of the +documentation on "tuples" including Microsoft's own is liberally sprinkled with references +to `System.ValueTuple`. It is probably safe to skate over such references. + +### Other Uses and Limitations + +Pattern matching is a particularly productive use for tuples. This +is covered in a later exercise. + +Tuples allow for some other minor stylistic flourishes: + +- Multiple assignment (particularly in constructors) .e.g `(this.field1, this.field2) = (arg1, arg2);` +- Swapping or recycling values e.g. `(a, b) = (b, a);` +- Use instead of a `struct` in a list +- Use as a dictionary key or the contents of a set. +- Use in LINQ. (LINQ is covered by later exercises). + +The documentation describes tuples as a lightweight mechanism and that is the key to +its successful use. Using a tuple instead of a class or struct can lead to tedious +repetition of its field types and possibly names. This applies particularly to +its use as a method argument or as the generic argument in collections. + +It is best to make use of tricks like multiple assignment and swapping judiciously. + +Relational operations other than equality and inequality are not supported. + +Note that tuples were introduced into the language relatively recently (C# 7) +so if you want to use them you should make sure your code base +is using [version][language-version] 7 or later of the language. + +[tuples]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples +[tuple-projection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuple-projection-initializers +[tuple-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples +[tuple-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#assignment-and-tuples +[tuple-return-values]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values +[tuple-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstruction +[udt-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstructing-user-defined-types +[system-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.tuple?view=netcore-3.1 +[system-value-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8?view=netcore-3.1 +[language-version]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version diff --git a/exercises/concept/tuples/.docs/hints.md b/exercises/concept/tuples/.docs/hints.md new file mode 100644 index 0000000000..0ce71dc00f --- /dev/null +++ b/exercises/concept/tuples/.docs/hints.md @@ -0,0 +1,15 @@ +### General + +- [Tuples][tuples]: shows how to define and use tuples. + +### 1. Analyze a phone number + +- Tuples are passed as a [return value][tuples-return]. + +### 2. Detect if a phone number is fake prefix code (555) + +- You can extract the value of a field with the same sort of dot syntax as you employ with `struct`s or `class`s. + +[tuples]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples +[tuples-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples +[tuples-return]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values diff --git a/exercises/concept/tuples/.docs/instructions.md b/exercises/concept/tuples/.docs/instructions.md new file mode 100644 index 0000000000..c08173254c --- /dev/null +++ b/exercises/concept/tuples/.docs/instructions.md @@ -0,0 +1,30 @@ +This exercise has you analyze phone numbers. + +You are asked to implement 2 features. + +Phone numbers passed to the routines are guaranteed to be in the form +NNN-NNN-NNNN e.g. 212-515-9876 and non-null. + +### 1. Analyze a phone number + +Your analysis should return 3 pieces of data + +1. An indication of whether the number has a New York dialing code ie. 212 as the first 3 digits +2. An indication of whether the number is fake having 555 as a prefix code in positions 5 to 7 (numbering from 1) +3. The last 4 digits of the number. + +Implement the (static) method `PhoneNumber.Analyze()` to produce the phone number info. + +```csharp +PhoneNumber.Analyze("631-555-1234"); +// => (false, true, "1234") +``` + +### 2. Detect if a phone number has a fake prefix code (555) + +Implement the (static) method `PhoneNumber.IsFake()` to detect whether the phone number is fake using the phone number info produced in task 1. + +```csharp +PhoneNumber.IsFake(PhoneNumbers.Analyze("631-555-1234")); +// => true +``` diff --git a/exercises/concept/tuples/.docs/introduction.md b/exercises/concept/tuples/.docs/introduction.md new file mode 100644 index 0000000000..fa89e2d77d --- /dev/null +++ b/exercises/concept/tuples/.docs/introduction.md @@ -0,0 +1,51 @@ +In C#, a tuple is a data structure which organizes data, holding two or more fields +of any type. + +A tuple is typically created by placing 2 or more expressions separated by comas, +within a set of parentheses. + +```csharp +string boast = "All you need to know"; +bool success = !string.IsNullOrWhiteSpace(boast); +(bool, int, string) tripple = (success, 42, boast); +``` + +A tuple can be used in assignment and initialization operations, as a return value or a method argument. + +Fields are extracted using dot syntax. By default, the first field is `Item1`, +the second `Item2`, etc. Non-default names are discussed below. + +```csharp +// initialization +(int, int, int) vertices = (90, 45, 45); + +// assignment +vertices = (60, 60, 60); + +// return value +(bool, int) GetSameOrBigger(int num1, int num2) +{ + return (num1 == num2, num1 > num2 ? num1 : num2); +} + +// method argument +int Add((int, int) operands) +{ + return operands.Item1 + operands.Item2; +} +``` + +Field names `Item1` etc. do not make for readable code. The code below shows +2 ways to name the fields of tuples. Note also, in the code below, that `var` can be used with tuples and the type inferred. This works equally well for tuples with named and unnamed fields. + +```csharp +// name items in declaration +(bool success, string message) results = (true, "well done!"); +bool mySuccess = results.success; +string myMessaage = results.message; + +// name items in creating expression +var results2 = (success: true, message: "well done!"); +bool mySuccess2 = results2.success; +string myMessaage2 = results2.message; +``` diff --git a/exercises/concept/tuples/.meta/Example.cs b/exercises/concept/tuples/.meta/Example.cs new file mode 100644 index 0000000000..902646b71a --- /dev/null +++ b/exercises/concept/tuples/.meta/Example.cs @@ -0,0 +1,14 @@ +public static class PhoneNumber +{ + public static (bool IsNewYork, bool IsFake, string LocalNumber) Analyze(string phoneNumber) + { + return (phoneNumber.Substring(0, 3) == "212" + , phoneNumber.Substring(4, 3) == "555" + , phoneNumber.Substring(8, 4)); + } + + public static bool IsFake((bool IsNewYork, bool IsFake, string LocalNumber) phoneNumberInfo) + { + return phoneNumberInfo.IsFake; + } +} diff --git a/exercises/concept/tuples/.meta/config.json b/exercises/concept/tuples/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/tuples/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/tuples/.meta/design.md b/exercises/concept/tuples/.meta/design.md new file mode 100644 index 0000000000..53c4918df9 --- /dev/null +++ b/exercises/concept/tuples/.meta/design.md @@ -0,0 +1,24 @@ +## Learning objectives + +- Know what a tuple is. +- Know how to define a tuple. +- Know how to name tuple fields. +- Know how to deconstruct tuples. +- Know that tuples are mutable. + +## Out of scope + +- The old `Tuple` class. +- Pattern matching on tuples. +- How to add tuple pattern matching to your own and built-in types. +- Know that tuples have structural equality. + +## Concepts + +- `tuples`: know what a tuple is; know how to define a tuple; know how to name tuple fields; know that tuples have structural equality; know how to deconstruct tuples; know that tuples are mutable. + +## Prequisites + +- `basics`: know how to define methods and variables. +- `strings`: obtaining sub-strings from a string +- `conditionals`: combining conditions. diff --git a/exercises/concept/tuples/Tuples.cs b/exercises/concept/tuples/Tuples.cs new file mode 100644 index 0000000000..632c5ce6fd --- /dev/null +++ b/exercises/concept/tuples/Tuples.cs @@ -0,0 +1,14 @@ +using System; + +public static class PhoneNumber +{ + public static (bool IsNewYork, bool IsFake, string LocalNumber) Analyze(string phoneNumber) + { + throw new NotImplementedException($"Please implement the (static) PhoneNumber.Analyze() method"); + } + + public static bool IsFake((bool IsNewYork, bool IsFake, string LocalNumber) phoneNumberInfo) + { + throw new NotImplementedException($"Please implement the (static) PhoneNumber.IsFake() method"); + } +} diff --git a/exercises/concept/tuples/Tuples.csproj b/exercises/concept/tuples/Tuples.csproj new file mode 100644 index 0000000000..74c13b2836 --- /dev/null +++ b/exercises/concept/tuples/Tuples.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/tuples/TuplesTest.cs b/exercises/concept/tuples/TuplesTest.cs new file mode 100644 index 0000000000..948245e331 --- /dev/null +++ b/exercises/concept/tuples/TuplesTest.cs @@ -0,0 +1,46 @@ +using Xunit; + +public class TuplesTest +{ + [Fact] + public void Analyze_non_fake_non_newyork() + { + Assert.Equal((false, false, "1234"), PhoneNumber.Analyze("631-502-1234")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Analyze_fake_non_newyork() + { + Assert.Equal((false, true, "1234"), PhoneNumber.Analyze("631-555-1234")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Analyze_non_fake_newyork() + { + Assert.Equal((true, false, "1234"), PhoneNumber.Analyze("212-502-1234")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Analyze_fake_newyork() + { + Assert.Equal((true, true, "1234"), PhoneNumber.Analyze("212-555-1234")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Analyze_fake_fake() + { + Assert.Equal((false, false, "1234"), PhoneNumber.Analyze("515-212-1234")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Is_Fake_fake() + { + Assert.True(PhoneNumber.IsFake(PhoneNumber.Analyze("212-555-1234"))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Is_Fake_non_fake() + { + Assert.False(PhoneNumber.IsFake(PhoneNumber.Analyze("555-212-1234"))); + } +} From 53d6af3af8af5a19c276ef30528db1974dab1fd1 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 25 Jun 2020 11:37:13 +0100 Subject: [PATCH 154/327] Add randomness Concept Exercise * randomness added files from v3-dashboard bot branch * randomness created tree and moved in files * [CI] Format C# code * randomness commit after messing up git. All looks ok Example.cs and instructions.md complete * randomness complete except hints.md and csharp config * randomness prettier * reandomness tweaks * randomness proofing * randomness cut-paste error fixed * Update languages/exercises/concept/randomness/.meta/design.md Co-authored-by: Erik Schierboom * randomness dropped thread safety as topic. * randomness improved RollDie test * Update languages/exercises/concept/randomness/RandomnessTests.cs Co-authored-by: Erik Schierboom * randomness hints.md * randomness all files complete after review Co-authored-by: github-actions[bot] Co-authored-by: Erik Schierboom --- exercises/concept/randomness/.docs/after.md | 42 +++++++++++++++++++ exercises/concept/randomness/.docs/hints.md | 15 +++++++ .../concept/randomness/.docs/instructions.md | 23 ++++++++++ .../concept/randomness/.docs/introduction.md | 1 + exercises/concept/randomness/.meta/Example.cs | 17 ++++++++ .../concept/randomness/.meta/config.json | 8 ++++ exercises/concept/randomness/.meta/design.md | 19 +++++++++ exercises/concept/randomness/Randomness.cs | 14 +++++++ .../concept/randomness/Randomness.csproj | 14 +++++++ .../concept/randomness/RandomnessTests.cs | 23 ++++++++++ 10 files changed, 176 insertions(+) create mode 100644 exercises/concept/randomness/.docs/after.md create mode 100644 exercises/concept/randomness/.docs/hints.md create mode 100644 exercises/concept/randomness/.docs/instructions.md create mode 100644 exercises/concept/randomness/.docs/introduction.md create mode 100644 exercises/concept/randomness/.meta/Example.cs create mode 100644 exercises/concept/randomness/.meta/config.json create mode 100644 exercises/concept/randomness/.meta/design.md create mode 100644 exercises/concept/randomness/Randomness.cs create mode 100644 exercises/concept/randomness/Randomness.csproj create mode 100644 exercises/concept/randomness/RandomnessTests.cs diff --git a/exercises/concept/randomness/.docs/after.md b/exercises/concept/randomness/.docs/after.md new file mode 100644 index 0000000000..9257c2c3a3 --- /dev/null +++ b/exercises/concept/randomness/.docs/after.md @@ -0,0 +1,42 @@ +In C# applications randomness is generally implemented using the `System.Random` class. + +This [article][system-random] is an excellent introduction to the subject. + +When becoming familiar with a library class it is always worth studying the [documentation][system-random] for properties and methods and their overloads. + +The coding exercise highlighted a number of issues: + +- The random number generator does not require a [seed][random-seedless]. +- `Random.Next()` can generate a range of integers +- `Random.Double()` can generate a double between 0 and 1 +- The upper bounds in `Next...()`, `Double()` and `Sample()` are **exclusive** so that `Random.Next(1,19)` will yield values from 1 to 18 but not 19. +- Once you have your random number you can do what you like with it + +There are 3 patterns for implementing the last point: + +- You can get the random number and manipulate it. In the case of the coding exercise this would consist of calling `Random.NextDouble()` and multiplying by 100. This [piece][random-use-case-array] discusses making random selections from an array. +- You can inherit from `System.Random` and override the `Sampple()` method. +- You can encapsulate an instance of `System.Random` as a member of a class of your own, for example [to generate booleans][random-use-cases]. + +The numbers generated by `Random` are not guaranteed to be unique. + +It is [recommended][random-thread-safety] that you instantiate `System.Random` as a static member. But, note that it is not thread safe. + +You may see documentation discouraging the use of seedless constructors. This mostly applies to .NET Framework rather than .NET Core (which is what _Exercism_ uses). For the full story read [this][random-multiple-instantiations]. + +You are advised not to use `System.Random` for crypto or security. See this [provider][crypto-provider] and this [number generator][crypto-rng]. + +##### Thread safety + +When applied in the context of library APIs "not thread safe" is simply shorthand for saying that, if you are likely to access instances of the class through multiple concurrent [threads][threading], you should provide your own thread synchronization mechanisms or, in the case of collections, look at the possibility of using a concurrent version of the class. In the absence of these precautions, [race conditions][so-race-conditions] are likely to occur. If your code base does not use multiple threads, and is not likely to, then this warning is of little concern. + +[system-random]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1 +[random-thread-safety]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#the-systemrandom-class-and-thread-safety +[random-use-cases]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#generate-random-boolean-values +[random-use-case-array]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#UniqueArray +[crypto-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=netcore-3.1 +[crypto-rng]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=netcore-3.1 +[random-seedless]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#instantiating-the-random-number-generator +[random-multiple-instantiations]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#avoiding-multiple-instantiations +[so-race-conditions]: https://stackoverflow.com/questions/34510/what-is-a-race-condition +[threading]: https://docs.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading diff --git a/exercises/concept/randomness/.docs/hints.md b/exercises/concept/randomness/.docs/hints.md new file mode 100644 index 0000000000..cf5a6f97f3 --- /dev/null +++ b/exercises/concept/randomness/.docs/hints.md @@ -0,0 +1,15 @@ +### General + +This [article][system-random] is an excellent introduction to the subject. + +### 1. Enable a wizards and warriors player to roll a die. + +This [article][random-integers] explains how to generate integers. + +### 2. Players need their strength. Provide a means to generate spell strength + +This [article][random-reals] explains how to generate real numbers. + +[system-random]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1 +[random-integers]: https://docs.microsoft.com/en-us/dotnet/api/system.random.next?view=netcore-3.1 +[random-reals]: https://docs.microsoft.com/en-us/dotnet/api/system.random.nextdouble?view=netcore-3.1 diff --git a/exercises/concept/randomness/.docs/instructions.md b/exercises/concept/randomness/.docs/instructions.md new file mode 100644 index 0000000000..c0282a1897 --- /dev/null +++ b/exercises/concept/randomness/.docs/instructions.md @@ -0,0 +1,23 @@ +Continuing the theme of the wizards and warriors game, it is time to add an all purpose die rolling method. This will be the traditional 18 sided die with numbers 1 to 18. Players also generate a spell strength. + +## 1. Enable a _wizards and warriors_ player to roll a die. + +Implement a `RollDie()` method on the `Player` class. + +```csharp +var player = new Player(); +player.RollDie(); +// => >= 1 <= 18 +``` + +## 2. Players need their strength. Provide a means to generate spell strength + +Implement a `GenerateSpellStregngth()` method on the player class. The spell strength is between 0.0 and 100.0. + +Note that spell strength must be a real number (not an integer) to reduce the possibility of a tie when the strengths of two adversaries are compared. + +```csharp +var player = new Player(); +player.GenerateSpellStrength(); +// => >= 0.0 < 100.0 +``` diff --git a/exercises/concept/randomness/.docs/introduction.md b/exercises/concept/randomness/.docs/introduction.md new file mode 100644 index 0000000000..264aec91ec --- /dev/null +++ b/exercises/concept/randomness/.docs/introduction.md @@ -0,0 +1 @@ +In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case. diff --git a/exercises/concept/randomness/.meta/Example.cs b/exercises/concept/randomness/.meta/Example.cs new file mode 100644 index 0000000000..3bfb5dc23b --- /dev/null +++ b/exercises/concept/randomness/.meta/Example.cs @@ -0,0 +1,17 @@ +using System; + +public class Player +{ + private static Random random = new Random(); + private const int DIE_HIGH = 18; + + public int RollDie() + { + return random.Next(1, DIE_HIGH + 1); + } + + public double GenerateSpellStrength() + { + return random.NextDouble() * 100; + } +} diff --git a/exercises/concept/randomness/.meta/config.json b/exercises/concept/randomness/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/randomness/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/randomness/.meta/design.md b/exercises/concept/randomness/.meta/design.md new file mode 100644 index 0000000000..96cd8310d9 --- /dev/null +++ b/exercises/concept/randomness/.meta/design.md @@ -0,0 +1,19 @@ +## Learning objectives + +- Know how to implement randomness with `System.Random` in C#. +- Know that no seed is required +- Know that both integers and real numbers can be generated +- Know that once generated random numbers can be easily used for many purposes (including non-numeric ones). +- Know about thread safety and how it relates to the `System.Random` class (discussion only). + +## Out of scope + +- Secure random numbers + +## Concepts + +- `randomness`: know how to implement randomness with `System.Random` in C#; know that no seed is required; know that both integers and real numbers can be generated; know that once generated random numbers can be easily used for many purposes (including non-numeric ones) + +## Prerequisites + +- `numbers` diff --git a/exercises/concept/randomness/Randomness.cs b/exercises/concept/randomness/Randomness.cs new file mode 100644 index 0000000000..f9555430b9 --- /dev/null +++ b/exercises/concept/randomness/Randomness.cs @@ -0,0 +1,14 @@ +using System; + +public class Player +{ + public int RollDie() + { + throw new NotImplementedException("Please implement the Player.RollDie() method"); + } + + public double GenerateSpellStrength() + { + throw new NotImplementedException("Please implement the Player.GenerateSpellStrength() method"); + } +} diff --git a/exercises/concept/randomness/Randomness.csproj b/exercises/concept/randomness/Randomness.csproj new file mode 100644 index 0000000000..206cf24cce --- /dev/null +++ b/exercises/concept/randomness/Randomness.csproj @@ -0,0 +1,14 @@ + + + + netcoreapp3.1 + + + + + + + + + + diff --git a/exercises/concept/randomness/RandomnessTests.cs b/exercises/concept/randomness/RandomnessTests.cs new file mode 100644 index 0000000000..133f1699f3 --- /dev/null +++ b/exercises/concept/randomness/RandomnessTests.cs @@ -0,0 +1,23 @@ +using Xunit; +using System; + +public class RandomnessTests +{ + [Fact] + public void RollDie() + { + var player = new Player(); + for (var i = 0; i < 100; i++) + { + Assert.InRange(player.RollDie(), 1, 18); + } + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GenerateSpellStrength() + { + var player = new Player(); + var strength = player.GenerateSpellStrength(); + Assert.InRange(strength, 0.0, 100.0); + } +} From f78fa0439fa780c6cb713c96781a729f5cb17973 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 26 Jun 2020 09:15:13 +0100 Subject: [PATCH 155/327] Implemented Concept exercise: equality * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * equality initial commit * added exercise template * equality substantially complete for draft PR * equality things forgotten * equality things mistaken * equality task clarification * equality additional afters * equality prettier * equality tweaked story * tuples tweaks * equality tweaks * equality after.md started * equality after.md tweaks * equality after.md WIP * equality after.md WIP * equality after.md WIP * equality after.md complete-ish * equality after.md tweaks * equality introduction.md * equality introduction.md tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * regular-expressions added reference to tuples * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * equality proofing * Apply suggestions from code review Co-authored-by: Erik Schierboom * Apply suggestions from code review Co-authored-by: Erik Schierboom * resource-cleanup after review * equality updated track's config.json * equality proofing Co-authored-by: Erik Schierboom --- exercises/concept/aa-template/.docs/after.md | 0 exercises/concept/aa-template/.docs/hints.md | 0 .../concept/aa-template/.docs/instructions.md | 0 .../concept/aa-template/.docs/introduction.md | 0 .../concept/aa-template/.meta/Example.cs | 0 .../concept/aa-template/.meta/config.json | 8 + exercises/concept/aa-template/.meta/design.md | 0 exercises/concept/aa-template/XXX.cs | 0 exercises/concept/aa-template/XXX.csproj | 13 ++ exercises/concept/aa-template/XXXTests.cs | 0 exercises/concept/equality/.docs/after.md | 152 ++++++++++++++++++ exercises/concept/equality/.docs/hints.md | 34 ++++ .../concept/equality/.docs/instructions.md | 86 ++++++++++ .../concept/equality/.docs/introduction.md | 27 ++++ exercises/concept/equality/.meta/Example.cs | 93 +++++++++++ exercises/concept/equality/.meta/config.json | 8 + exercises/concept/equality/.meta/design.md | 31 ++++ exercises/concept/equality/Equality.cs | 55 +++++++ exercises/concept/equality/Equality.csproj | 13 ++ exercises/concept/equality/EqualityTests.cs | 86 ++++++++++ 20 files changed, 606 insertions(+) create mode 100644 exercises/concept/aa-template/.docs/after.md create mode 100644 exercises/concept/aa-template/.docs/hints.md create mode 100644 exercises/concept/aa-template/.docs/instructions.md create mode 100644 exercises/concept/aa-template/.docs/introduction.md create mode 100644 exercises/concept/aa-template/.meta/Example.cs create mode 100644 exercises/concept/aa-template/.meta/config.json create mode 100644 exercises/concept/aa-template/.meta/design.md create mode 100644 exercises/concept/aa-template/XXX.cs create mode 100644 exercises/concept/aa-template/XXX.csproj create mode 100644 exercises/concept/aa-template/XXXTests.cs create mode 100644 exercises/concept/equality/.docs/after.md create mode 100644 exercises/concept/equality/.docs/hints.md create mode 100644 exercises/concept/equality/.docs/instructions.md create mode 100644 exercises/concept/equality/.docs/introduction.md create mode 100644 exercises/concept/equality/.meta/Example.cs create mode 100644 exercises/concept/equality/.meta/config.json create mode 100644 exercises/concept/equality/.meta/design.md create mode 100644 exercises/concept/equality/Equality.cs create mode 100644 exercises/concept/equality/Equality.csproj create mode 100644 exercises/concept/equality/EqualityTests.cs diff --git a/exercises/concept/aa-template/.docs/after.md b/exercises/concept/aa-template/.docs/after.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/.docs/hints.md b/exercises/concept/aa-template/.docs/hints.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/.docs/instructions.md b/exercises/concept/aa-template/.docs/instructions.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/.docs/introduction.md b/exercises/concept/aa-template/.docs/introduction.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/.meta/Example.cs b/exercises/concept/aa-template/.meta/Example.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/.meta/config.json b/exercises/concept/aa-template/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/aa-template/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/aa-template/.meta/design.md b/exercises/concept/aa-template/.meta/design.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/XXX.cs b/exercises/concept/aa-template/XXX.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/aa-template/XXX.csproj b/exercises/concept/aa-template/XXX.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/aa-template/XXX.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/aa-template/XXXTests.cs b/exercises/concept/aa-template/XXXTests.cs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/equality/.docs/after.md b/exercises/concept/equality/.docs/after.md new file mode 100644 index 0000000000..c6a6b7ee06 --- /dev/null +++ b/exercises/concept/equality/.docs/after.md @@ -0,0 +1,152 @@ +The coding exercise illustrates a number of properties of equality in C#: + +### `Object.Equals()` + +#### Topics covered by the coding exercise + +- Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. This is considered more idiomatic than using the [`Equals()`][object-equals] method which is also available with these types. Java programmers should be alert, when dealing with strings, to the fact that `==` compares by value in C# but by reference in Java when returning to their former language. +- Reference types (Instances of classes) are compared using the `Equals()` method inherited from `object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `object`'s implementation will suffice. If not, you need to override `object.Equals()`. +- If you know that all the instances of your class are created in one place, say characters in some game or simulation then reference equality is sufficient. However, it is likely that multiple instances of the same real-world entity will be created (for example, from a database, by user input, via a web request). In this case values that uniquely identify the entity must be tested for equality. Therefore `Equals()` must be overridden. +- An overridden `Equals()` will contain equality tests on members of simple types using `==` and reference types with recursive calls to `Equals()`. + +```csharp +class StatusBar +{ + private readonly int width = 200, height = 20; + + public override bool Equals(object other) + { + // ... null and type checks and performance optimisations + return width == (other as StatusBar).width && height == (other as StatusBar).height; + } +} +class Window +{ + private readonly string title = "Main"; + private readonly StatusBar statusBar = new StatusBar(); + + public override bool Equals(object other) + { + // ... null and type checks and performance optimisations + return title == (other as Window).title && statusBar.Equals((other as Window).statusBar); + } +} + +``` + +- The static method `object.ReferenceEquals()` is used to compare two objects to detect if they are one and the same instance. This provides clarity and is a necessity where `Equals()` and `==` have been overridden/overloaded. + +```csharp +var winA = new Window(); // above code shows that all windows are equal +var winB = new Window(); +ReferenceEquals(winA, winB); +// => false +var winC = winA; +ReferenceEquals(winA, winC); +// => true +``` + +#### Ancillary topics + +- In addition to `public override bool Equals(object obj)` IDEs typically generate the overload `protected bool Equals(FacialFeatures other)` for use when inheritance is involved. A derived class can call the base classe's `Equals()` and then add its own test. +- Do not use `==` unless you have [overloaded][operator-overloading] the `==` operator, as well as the `Equals()` method in your class (see the `operator-overloading` exercise) or you care only that the references are equal. +- Equality tests in [`struct`s][struct] are dealt with in the `structs` exercise. +- Equality of [`tuple`s][tuples-equality] is dealt with in the `tuples` exercise. +- Many developers rely on their IDEs to provide implementation of equality methods as these take care of all the minutiae of equality. For instance, JetBrains' RIDER (v 2020.1) generates the following equality methods for a class: + +```csharp +protected bool Equals(T other) +{ + return field1 == other.field1 && field2.Equals(other.field2); +} + +public override bool Equals(object obj) +{ + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((T) obj); +} +``` + +- Be careful if you decide to improve on the code generated by your IDE. That code is generally bullet-proof against nulls and mistyped objects and fairly well optimized. +- Tests for the equality of [delegates][delegate-equality] is not specifically discussed in the exercise. +- There are no built in equality tests for arrays nor most collections. [LINQ][linq] (discussed in later exercises) provides [`SequenceEquals()`][sequence-equal] but in the absence of LINQ it is a matter of iterating through both collections and comparing items individually. +- For a discussion of how to use `==` and `!=` with your own classes see the `operator-overloading` exercise. + +### `Object.GetHashCode()` + +- [`object.GetHashCode()`][get-hash-code] returns a hash code in the form of a 32 bit integer. The hash code is used by dictionary and set classes such as [`Dictionary`][dictionary] and [`HashSet`][hash-set] to store and retrieve objects in a performant manner. In the case of dictionaries the [hashing][wiki-hash] relates to the keys. +- There is an expectation amongst C# developers that if you override `Equals()` you will also override `GetHashCode()`. There is a relationship between `Equals()` and `GetHashCode()` that must hold true for correct behavior of dictionary and hash set classes and any others that use a hash code. You are expected to implement the method so that no traps are laid for maintainers who might add a hash code based collection at a later time. +- The relationship between hash code and equality is that if two objects are equal (`Equal()` returns true) then `GetHashCode()` for the two objects must return the same value. This does not apply in the reverse direction. It is not symmetrical. Picture a lookup function that first goes to a "bucket" based on the hash code and then picks out the particular item using the equality test. +- The easiest way to create a hashcode is to call [`HashCode.Combine()`][hash-code-combine] passing in the values used in the equality test (or a subset). Bear in mind the more information you provide to `Combine()` the more performant the hash implementation is likely to be. + +```csharp +public class Assessment +{ + private int rating; + private Person boss; + + public override int GetHashCode() + { + return HashCode.Combine(rating, boss); + } +} +``` + +- The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be [immutable][wiki-immutable]. Other approaches run the risk of creating gotchas for maintainers. Immutability is discussed in other exercises. +- It is possible that you can design a better hashcode than that produced by the library routines but either it's because you have a detailed understanding of the data's characteristics or because it is a very simple collection where values can be used directly without hashing. It may not be worth the extra effort. + +### Performance Enhancements + +To improve performance slightly, especially where objects belong to collections you can add an overloaded member `public bool Equals(T other)`. + +This will save a certain amount of type checking for reference types and will save a boxing step for value types as they will not need to be converted to an object (boxed) as an argument to `public override bool Equals(object other)`. + +If you add the interface `IEquatable` to your class this will require the overload to be implemented. Unless your code contains routines that take objects of type `IEquatable` (and presumably do something interesting relating to equality irrespective of the implementing class) there is really no other compelling to include the interface. + +### `IEqualityComparer` + +If you have a class that can be uniquely identified in two different ways, say a `Person` class that has a SSID and a unique email address then .NET provides a means to allow two different collections to use different hash-code and equality tests. Each can have an different implementation of `IEqualityComparer` with its own an `Equals()` and a `GetHashCode()` method. You can have a dictionary keyed on SSID and another keyed on email address. + +Where `IEqualityComparer` is in play you would typically still override `Equals()` and `GetHashCode()` on your item class to avoid problems outside the collection classes. + +One consideration when using `IEqualityComparer` is that private methods etc. will not be available for the equality test. + +If only one hashed collection is in play then it may be better to avoid `IEqualityComparer` and encapsulate equality and hash code in the object itself. It is not ideal, in the first place, that a key dependency such as that between object and hashed collection cannot be enforced by the compiler but with the hashing and comparison logic elsewhere it would be even easier for a maintainer to make changes to a class's members without regard to the consequences for the collection. + +### Note on floating-point equality + +One primitive that can challenge the unwary coder is testing the [equality of floating-point values][0.30000000000000004.com]. This is discussed in the _after.md_ document for the `floating-point-numbers` exercise. + +### Equality and Inheritance + +This [article][so-equals-inheritance] shows some of the decisions that have to be made with regard to equality and inheritance. They will only concern you if you are manipulating instances of a class and a derived class and need to test the equality between the two. + +### General Informaton + +- [Equality][equality]: how equality comparisons work in C#, including reference- and value type equality. +- [HashCode][hash-code]: how to create and combine hash codes +- [GetHashCode][get-hash-code]: API documentation +- [HashSet][hash-set]: API documentation + +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons +[equatable]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type +[equality-comparer]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iequalitycomparer-1?view=netcore-3.1 +[hash-set]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode?view=netcore-3.1 +[get-hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 +[delegate-equality]: https://docs.microsoft.com/en-us/dotnet/api/system.delegate.equals?view=netcore-3.1 +[sequence-equal]: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?redirectedfrom=MSDN&view=netcore-3.1#System_Linq_Enumerable_SequenceEqual__1_System_Collections_Generic_IEnumerable___0__System_Collections_Generic_IEnumerable___0__ +[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[so-equals-inheritance]: https://stackoverflow.com/questions/22154799/equals-method-inheritance-confusion +[object-equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ +[so-hashcode-equals]: https://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netcore-3.1 +[wiki-hash]: https://en.wikipedia.org/wiki/Hash_function +[hash-code-combine]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=netcore-3.1 +[wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object +[struct]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct +[tuples-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/tuple-equality diff --git a/exercises/concept/equality/.docs/hints.md b/exercises/concept/equality/.docs/hints.md new file mode 100644 index 0000000000..538635cf70 --- /dev/null +++ b/exercises/concept/equality/.docs/hints.md @@ -0,0 +1,34 @@ +### General + +- [Equality][equality]: how equality comparisons work in C#, including reference- and value type equality. +- [HashCode][hash-code]: how to create and combine hash codes +- [GetHashCode][get-hash-code]: API documentation +- [HashSet][hash-set]: API documentation + +## 1. Ensure that facial features match + +Comparing reference types by value is discussed in detail in this [article][value-equality]. + +## 2. Authenticate the system administrator + +This is simply a case of applying the lessons learnt in task 1 in a trivially recursive manner. + +## 3. Register new identities + +The most performant, and "natural", way to handle a collection of unique values is by using a [hash set][hash-set]. + +## 4. Prevent invalid identities being authenticated + +Consider the [`HashSet.Contains()`][hash-set-contains] method. + +## 5. Add diagnostics to detect multiple attempts to authenticate + +This [documentation][reference-equality] addresses the issue of comparing instances as opposed to values. + +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons +[hash-set]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode?view=netcore-3.1 +[get-hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 +[reference-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons#reference-equality +[value-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type +[hash-set-contains]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1.contains?view=netcore-3.1 diff --git a/exercises/concept/equality/.docs/instructions.md b/exercises/concept/equality/.docs/instructions.md new file mode 100644 index 0000000000..25dcc2cde7 --- /dev/null +++ b/exercises/concept/equality/.docs/instructions.md @@ -0,0 +1,86 @@ +You are working on a system to simplify the login process for your organization's network. The tasks concern the authentication part. The system uses facial recognition to prove identity. + +In all occurrences the eye color parameter is guaranteed to be non-null. + +## 1. Ensure that facial features match + +Implement `Authenticator.AreSameFace()` to check that two faces match. + +Add equality reoutines for the `FacialFeatures` class. + +```csharp +Authenticator.AreSameFace(new FacialFeatures("green", 0.9m), new FacialFeatures("green", 0.9m); +// => true +Authenticator.AreSameFace(new FacialFeatures("blue", 0.9m), new FacialFeatures("green", 0.9m); +// => false +``` + +## 2. Authenticate the system administrator + +Despite your protests the system administrator insists on having a built-in identity during acceptance testing so that they can always be authenticated. + +The admin's email is admin@exerc.ism. They have green eyes and a philtrum with a width of 0.9. + +Add equality routines for the `Identity` class. + +Implement the `Authenticator.IsAdmin()` method to check that the identity passed in matches that of the administrator. + +```csharp +var authenticator = new Authenticator(); +authenticator.IsAdmin(new Identity("admin@exerc.ism", new FacialFeatures("green", 0.9m))); +// => true +authenticator.IsAdmin(new Identity("admin@thecompetition.com", new FacialFeatures("green", 0.9m))); +// => false +``` + +## 2. Prevent invalid identities being authenticated + +Implement the `Authenticator.IsRegistered()` method and ensure it returns false when no matching identity has been registered. + +```csharp +var authenticator = new Authenticator(); +authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.8m))); +// => false +``` + +## 3. Register new identities + +Implement the `Authenticator.Register()` method which stores an identity on the authenticator itself such that calls to `IsRegistered()` will return `true` for this identity: otherwise `IsRegisterd()` returns `false`. + +To detect duplicated attempts to register an identity, if the identity has already been registered then `false` is returned by `Authenticator.Register()`, otherwise `true`. + +```csharp +var authenticator = new Authenticator(); +authenticator.Register(new Identity("tunde@thecompetition.com", new FacialFeatures("blue", 0.9m))); +// => true +authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m))); +// => true +authenticator.Register(new Identity("tunde@thecompetition.com", new FacialFeatures("blue", 0.9m))); +// => false +``` + +## 4. Prevent invalid identities being authenticated + +Implement the `Authenticator.IsRegistered()` method and ensure it returns false when no identities have been registered. + +```csharp +var authenticator = new Authenticator(); +authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.8m))); +// => false +``` + +## 5. Add diagnostics to detect multiple attempts to authenticate + +A bug has been reported whereby the `Authenticator.IsRegistered()` nethod is called multiple times in quick succession for the same identity. You believe that there is some sort of "bounce" problem where the exact same record is being submitted multiple times. Your task is to add a diagnostic routine `Authenticator.AreSameObject()` to support any testing that's undertaken. The routine compares to objects and returns `true` if they are the exact same instance otherwise `false`. + +```csharp +var identityA = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); +var identityB = identityA; +Authenticator.AreSameObject(identityA, identityB); +// => true + +var identityC = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); +var identityD = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); +Authenticator.AreSameObject(identityC, identityD); +// => false +``` diff --git a/exercises/concept/equality/.docs/introduction.md b/exercises/concept/equality/.docs/introduction.md new file mode 100644 index 0000000000..3642db959b --- /dev/null +++ b/exercises/concept/equality/.docs/introduction.md @@ -0,0 +1,27 @@ +This exercise looks at how you test for equality and the importance of hash codes. + +### `Object.Equals()` + +Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. + +Reference types (Instances of classes) are compared using the `Equals()` method inherited from `Object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `Object`'s implementation will suffice. If not, you need to override `object.Equals()`. + +If you know that all the instances of your class are created in one place, say characters in some game or simulation then reference equality is sufficient. However, it is likely that multiple instances of the same real-world entity will be created (from a database, by user input, via a web request). In this case values that uniquely identify the entity must be tested for equality. Therefore `Equals()` must be overridden and appropriate data members of your class are tested for equality. + +An overridden `Equals()` method will contain equality tests on members of simple types using `==` and reference types with recursive calls to `Equals()`. + +The `Object` class provides appropriate methods to compare two objects to detect if they are one and the same instance. + +### `Object.GetHashCode()` + +The `Object.GetHashCode()` method returns a hash code in the form of a 32 bit integer. The hash code is used by _dictionary_ and _set_ classes such as `Dictionary` and `HashSet`to store and retrieve objects in a performant manner. + +The relationship between hash code and equality is that if two objects are equal (`Equal()` returns true) then `GetHashCode()` for the two objects must return the same value. This does not apply in the reverse direction. It is not symmetrical. Just because two objects have the same hashcode they do not have to be equal. Picture a lookup function that first goes to a "bucket" based on the hash code and then picks out the particular item using the equality test. + +The HashCode library API documentation discusses the best way to generate a hash code + +The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be immutable. Other approaches run the risk of creating gotchas for maintainers. + +### HashSet + +The `HashSet` library class provides a good mechanism for storing unique values. diff --git a/exercises/concept/equality/.meta/Example.cs b/exercises/concept/equality/.meta/Example.cs new file mode 100644 index 0000000000..20c143543e --- /dev/null +++ b/exercises/concept/equality/.meta/Example.cs @@ -0,0 +1,93 @@ +using System; +using System.Collections.Generic; + +public class FacialFeatures +{ + public string EyeColor { get; } + public decimal PhiltrumWidth { get; } + + public FacialFeatures(string eyeColor, decimal philtrumWidth) + { + EyeColor = eyeColor; + PhiltrumWidth = philtrumWidth; + } + + protected bool Equals(FacialFeatures other) + { + return EyeColor == other.EyeColor && PhiltrumWidth.Equals(other.PhiltrumWidth); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((FacialFeatures)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(EyeColor, PhiltrumWidth); + } +} + +public class Identity +{ + public string Email { get; } + public FacialFeatures FacialFeatures { get; } + + public Identity(string email, FacialFeatures facialFeatures) + { + Email = email; + FacialFeatures = facialFeatures; + } + + protected bool Equals(Identity other) + { + return Email == other.Email && Equals(FacialFeatures, other.FacialFeatures); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Identity)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Email, FacialFeatures); + } +} + +public class Authenticator +{ + private Identity admin = new Identity("admin@exerc.ism", new FacialFeatures("green", 0.9m)); + private HashSet identities = new HashSet(); + + public static bool AreSameFace(FacialFeatures faceA, FacialFeatures faceB) + { + return faceA.Equals(faceB); + } + + public bool IsAdmin(Identity identity) + { + return identity.Equals(admin); + } + + public bool Register(Identity identity) + { + return identities.Add(identity); + } + + public bool IsRegistered(Identity identity) + { + return identities.Contains(identity); + } + + public static bool AreSameObject(Identity identityA, Identity identityB) + { + return ReferenceEquals(identityA, identityB); + } +} diff --git a/exercises/concept/equality/.meta/config.json b/exercises/concept/equality/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/equality/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/equality/.meta/design.md new file mode 100644 index 0000000000..e6f75e69fc --- /dev/null +++ b/exercises/concept/equality/.meta/design.md @@ -0,0 +1,31 @@ +## Learning objectives + +- Know how to check for equality and inequality. +- Know that equality works by default for value and reference types. +- Know how to customize equality checks using `Equals` and `GetHashCode()`. +- Know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them (discussion only). +- Know how to use `System.Collections.Generic.HashSet` and its relationship to `GetHashCode()`. + +## Out of scope + +- Collection equality. +- `struct` equality +- Equality of primitives + +## Concepts + +This Concepts Exercise's Concepts are: + +- `equality`: know how to check for equality and inequality; know how reference equality differs from structural equality; know that equality works by default for value and reference types; know how to customize equality checks using `Equals` and `GetHashCode()`; know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them. +- `sets`: hash sets as provided by C#/.NET. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `generic-types`: needed for understanding the `IEquatable` interface. +- `interfaces`: know how to implement interfaces +- `inheritance`: know that all types are derived from `object`. +- `classes`: know how to define and work with classes. +- `lists`: Know what a collection looks like and how it is generally used. +- `explicit-casts`: object -> T diff --git a/exercises/concept/equality/Equality.cs b/exercises/concept/equality/Equality.cs new file mode 100644 index 0000000000..fa44009193 --- /dev/null +++ b/exercises/concept/equality/Equality.cs @@ -0,0 +1,55 @@ +using System; + +public class FacialFeatures +{ + public string EyeColor { get; } + public decimal PhiltrumWidth { get; } + + public FacialFeatures(string eyeColor, decimal philtrumWidth) + { + EyeColor = eyeColor; + PhiltrumWidth = philtrumWidth; + } + // TODO: implement equality and GetHashCode() methods +} + +public class Identity +{ + public string Email { get; } + public FacialFeatures FacialFeatures { get; } + + public Identity(string email, FacialFeatures facialFeatures) + { + Email = email; + FacialFeatures = facialFeatures; + } + // TODO: implement equality and GetHashCode() methods +} + +public class Authenticator +{ + public static bool AreSameFace(FacialFeatures faceA, FacialFeatures faceB) + { + throw new NotImplementedException("Please implement the (static) Authenticator.AreSameFace() method"); + } + + public bool IsAdmin(Identity identity) + { + throw new NotImplementedException("Please implement the Authenticator.IsAdmin() method"); + } + + public bool Register(Identity identity) + { + throw new NotImplementedException("Please implement the Authenticator.Register() method"); + } + + public bool IsRegistered(Identity identity) + { + throw new NotImplementedException("Please implement the Authenticator.IsRegistered() method"); + } + + public static bool AreSameObject(Identity identityA, Identity identityB) + { + throw new NotImplementedException("Please implement the Authenticator.AreSameObject() method"); + } +} diff --git a/exercises/concept/equality/Equality.csproj b/exercises/concept/equality/Equality.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/equality/Equality.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/equality/EqualityTests.cs b/exercises/concept/equality/EqualityTests.cs new file mode 100644 index 0000000000..94d575c4fb --- /dev/null +++ b/exercises/concept/equality/EqualityTests.cs @@ -0,0 +1,86 @@ +using Xunit; + +public class EqualityTests +{ + [Fact] + public void IsAdmin_with_admin() + { + var authenticator = new Authenticator(); + Assert.True(authenticator.IsAdmin(new Identity("admin@exerc.ism", new FacialFeatures("green", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsAdmin_with_wrong_email() + { + var authenticator = new Authenticator(); + Assert.False(authenticator.IsAdmin(new Identity("admin@thecompetition.com", new FacialFeatures("green", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AreSameFace_yes() + { + Assert.True(Authenticator.AreSameFace(new FacialFeatures("green", 0.9m), + new FacialFeatures("green", 0.9m))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AreSameFace_no() + { + Assert.False(Authenticator.AreSameFace(new FacialFeatures("green", 0.9m), + new FacialFeatures("blue", 0.9m))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsAdmin_with_wrong_face() + { + var authenticator = new Authenticator(); + Assert.False(authenticator.IsAdmin(new Identity("admin@exerc.ism", new FacialFeatures("blue", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Register_new_identity() + { + var authenticator = new Authenticator(); + Assert.True(authenticator.Register(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Register_existing_identity() + { + var authenticator = new Authenticator(); + authenticator.Register(new Identity("tunde@thecompetition.com", new FacialFeatures("blue", 0.9m))); + Assert.False(authenticator.Register(new Identity("tunde@thecompetition.com", new FacialFeatures("blue", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsRegistered_existing_identity() + { + var authenticator = new Authenticator(); + authenticator.Register(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m))); + Assert.True(authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsRegistered_non_existent_identity() + { + var authenticator = new Authenticator(); + authenticator.Register(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m))); + Assert.False(authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.8m)))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AreSameObject_same_objects() + { + var identityA = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); + Assert.True(Authenticator.AreSameObject(identityA, identityA)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AreSameObject_different_objects() + { + var identityA = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); + var identityB = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); + Assert.False(Authenticator.AreSameObject(identityA, identityB)); + } + +} From 98dac09d897e3869e480afd3288824610fcd749a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Fri, 26 Jun 2020 16:16:59 +0200 Subject: [PATCH 156/327] Remove aa-template files --- exercises/concept/aa-template/.docs/after.md | 0 exercises/concept/aa-template/.docs/hints.md | 0 exercises/concept/aa-template/.docs/instructions.md | 0 exercises/concept/aa-template/.docs/introduction.md | 0 exercises/concept/aa-template/.meta/Example.cs | 0 exercises/concept/aa-template/.meta/config.json | 8 -------- exercises/concept/aa-template/.meta/design.md | 0 exercises/concept/aa-template/XXX.cs | 0 exercises/concept/aa-template/XXX.csproj | 13 ------------- exercises/concept/aa-template/XXXTests.cs | 0 10 files changed, 21 deletions(-) delete mode 100644 exercises/concept/aa-template/.docs/after.md delete mode 100644 exercises/concept/aa-template/.docs/hints.md delete mode 100644 exercises/concept/aa-template/.docs/instructions.md delete mode 100644 exercises/concept/aa-template/.docs/introduction.md delete mode 100644 exercises/concept/aa-template/.meta/Example.cs delete mode 100644 exercises/concept/aa-template/.meta/config.json delete mode 100644 exercises/concept/aa-template/.meta/design.md delete mode 100644 exercises/concept/aa-template/XXX.cs delete mode 100644 exercises/concept/aa-template/XXX.csproj delete mode 100644 exercises/concept/aa-template/XXXTests.cs diff --git a/exercises/concept/aa-template/.docs/after.md b/exercises/concept/aa-template/.docs/after.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/.docs/hints.md b/exercises/concept/aa-template/.docs/hints.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/.docs/instructions.md b/exercises/concept/aa-template/.docs/instructions.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/.docs/introduction.md b/exercises/concept/aa-template/.docs/introduction.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/.meta/Example.cs b/exercises/concept/aa-template/.meta/Example.cs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/.meta/config.json b/exercises/concept/aa-template/.meta/config.json deleted file mode 100644 index 315b869235..0000000000 --- a/exercises/concept/aa-template/.meta/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ] -} diff --git a/exercises/concept/aa-template/.meta/design.md b/exercises/concept/aa-template/.meta/design.md deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/XXX.cs b/exercises/concept/aa-template/XXX.cs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/exercises/concept/aa-template/XXX.csproj b/exercises/concept/aa-template/XXX.csproj deleted file mode 100644 index e7a827a208..0000000000 --- a/exercises/concept/aa-template/XXX.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - netcoreapp3.1 - - - - - - - - - diff --git a/exercises/concept/aa-template/XXXTests.cs b/exercises/concept/aa-template/XXXTests.cs deleted file mode 100644 index e69de29bb2..0000000000 From 2e5511038df8c74b8ef23f8816deb709e9fc4db9 Mon Sep 17 00:00:00 2001 From: Mike May Date: Sun, 28 Jun 2020 20:28:05 +0100 Subject: [PATCH 157/327] Add analyzer and representer functionality --- exercises/concept/tuples/.meta/design.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/exercises/concept/tuples/.meta/design.md b/exercises/concept/tuples/.meta/design.md index 53c4918df9..b077232e57 100644 --- a/exercises/concept/tuples/.meta/design.md +++ b/exercises/concept/tuples/.meta/design.md @@ -22,3 +22,15 @@ - `basics`: know how to define methods and variables. - `strings`: obtaining sub-strings from a string - `conditionals`: combining conditions. + +## Representer + +See [this issue][representer-issue]: handle tuple field names correctly in the [representer][representer]. + +## Analyzer + +See [this representer issue][representer-issue]: handle tuple field names correctly in the [analyzer][analyzer]. + +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer +[representer-issue]: https://github.com/exercism/csharp-representer/issues/3 From dc816fff41b817af71b25eb9963a3163f677691d Mon Sep 17 00:00:00 2001 From: mirko Date: Tue, 30 Jun 2020 08:02:39 +0200 Subject: [PATCH 158/327] remove unused link reference --- exercises/concept/numbers/.meta/design.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index 2b83d28875..fa0e0262fc 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -22,5 +22,3 @@ This exercise's prerequisites Concepts are: - `basics`: know how to define methods. - -[docs.microsoft.com-numbers]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/intro-to-csharp/numbers-in-csharp-local From 65e361803f8bf23d2b3a0b6a0485a04dd8d4312c Mon Sep 17 00:00:00 2001 From: mirko Date: Tue, 30 Jun 2020 08:03:06 +0200 Subject: [PATCH 159/327] remove unused link reference --- exercises/concept/arrays/.meta/design.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index f755a7b35e..414b7a8106 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -35,5 +35,3 @@ This exercise's prerequisites Concepts are: - `classes`: know how to work with fields. - `booleans`: know what a `bool` is. - `basics`: know how to work with `integers` and how to assign and update variables. - -[docs.microsoft.com-string]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1 From 7e1198805ba6b8617aa1c6d9fe275f1be9628968 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 30 Jun 2020 14:37:29 +0100 Subject: [PATCH 160/327] added concept exercise: parameters * added exercise template * parameters initial commit * parameters for draft PR * parameters making docs conformant * parameters spelling fix * equality tweaks * parameters added after.md text * parameters typos * parameters introductio.md * parameters fixed copy/paste error * parameters tweaks to docs * parameters proofing * parameters typo * parameters dropped otiose files * parameters review points * parameters review points * parameters review points * parameters ready to make PR non-draft --- exercises/concept/parameters/.docs/after.md | 90 +++++++++++++++++++ exercises/concept/parameters/.docs/hints.md | 17 ++++ .../concept/parameters/.docs/instructions.md | 62 +++++++++++++ .../concept/parameters/.docs/introduction.md | 47 ++++++++++ exercises/concept/parameters/.meta/Example.cs | 78 ++++++++++++++++ .../concept/parameters/.meta/config.json | 8 ++ exercises/concept/parameters/.meta/design.md | 27 ++++++ exercises/concept/parameters/Parameters.cs | 54 +++++++++++ .../concept/parameters/Parameters.csproj | 13 +++ .../concept/parameters/ParametersTests.cs | 57 ++++++++++++ 10 files changed, 453 insertions(+) create mode 100644 exercises/concept/parameters/.docs/after.md create mode 100644 exercises/concept/parameters/.docs/hints.md create mode 100644 exercises/concept/parameters/.docs/instructions.md create mode 100644 exercises/concept/parameters/.docs/introduction.md create mode 100644 exercises/concept/parameters/.meta/Example.cs create mode 100644 exercises/concept/parameters/.meta/config.json create mode 100644 exercises/concept/parameters/.meta/design.md create mode 100644 exercises/concept/parameters/Parameters.cs create mode 100644 exercises/concept/parameters/Parameters.csproj create mode 100644 exercises/concept/parameters/ParametersTests.cs diff --git a/exercises/concept/parameters/.docs/after.md b/exercises/concept/parameters/.docs/after.md new file mode 100644 index 0000000000..019f5aafc3 --- /dev/null +++ b/exercises/concept/parameters/.docs/after.md @@ -0,0 +1,90 @@ +The coding exercise illustrates a number of properties of parameters: + +- Parameters [passed][passing-parameters] without a modifier (such as `out` or `ref`) are passed by value. That is to say that the parameter can be used and assigned to in the called method but any changes will have no effect on the caller. +- When a reference to an array or an instance of a class is a parameter the elements/fields of that instance can be changed by the called method and the changes seen by the caller. This applies irrespective of whether the `ref` modifier is present. +- A parameter with the [`out`][out-parameter] modifier conveys a value back from the called method to the caller. The parameter can be passed to the called method without being initialized and in any case it is treated within the called method as if, on entry, it had not been initialized. An understanding of the behavior and rules regarding parameter modifiers can be gained most easily through examples (see below) and compiler messages. + +```csharp +void Foo(out int val) +{ + val = 42; +} +void Bar(int val) +{ + val = 42; +} + +int importantValue = 1729; +Foo(out importantValue); +var result = importantValue == 42; +// => true + +importantValue = 1729; +Bar(importantValue); +result = importantValue == 1729; +// => true +``` + +- `out` parameters must be assigned to within a called method. + +- A parameter with the [`ref`][ref-parameter] modifier passes a value into a called method. When the method returns the caller will find any updates made by the called method in that parameter. + +```csharp +void Foo(ref int val) +{ + val *= 7; +} + +int importantValue = 6; +Foo(ref importantValue); +return importantValue; +// => 42 +``` + +-`ref` parameters must be variables as the called method will be operating directly on the parameter as seen by the caller. + +- The `out` and `ref` modifiers are required both in the called method signature and at the call site. +- `out` parameters can be declared inline at the call site viz: `Foo(out int importantValue);` +- If you make a call to a method which has `out` parameters but you are not interested in the value assigned to one or more of them then you can use the [discard][discard] dummy variable `_`, as in: `Foo(out int _);` + +All the rules regarding `ref` and `out` parameters are enforced by the compiler. + +[`in`][in-parameter] parameters also exist but they are principally a performance optimisation and are discussed in the `structs` exercise where they are most relevant. + +The documentation linked to above is summarised below: + +- [passing-parameters][passing-parameters]: explains how values can be passed as arguments. Note that the subject of structs+parameters is discussed in the `structs` exercise. +- [ref-parameter][ref-parameter]: describes how `ref` parameters work. +- [out-parameter][out-parameter]: describes how `out` parameters work. + +When studying the documentation note that it uses the following terms: + +- parameter / formal parameter: refers to the parameter as seen by the called method. +- argument: refers to the parameter as seen by the caller. + +[Arguably][so-tuples-vs-out] much of the value of `out` parameters has been eliminated by the introduction of `tuples` in C# 7. The `tuples` exercise shows `tuples` being used to return multiple values. + +Whilst `ref` is easy to use and has no performance penalties it is worth seeing how the problems it addresses are dealt with in a particular code base before using it widely. There are alternatives such as passing in by-value and using the value from the called method's return statement. Again, `tuples` can play a role. + +You will see from the [documentation][ref-parameter] that `out` and `ref` cannot be used in certain situations but you can ignore them for now. The compiler will let you know whwn such situations arise. + +Note that `optional parameters` and `named arguments` are discussed in the `method-overloading` exercise. + +The related topics of [`ref local`][ref-local] and [`ref return`][ref-return] are discussed elsewhere. + +### Stack Allocations + +The rules regarding parameters and their modifiers are sufficiently straightforward that you can take them at face value and understand them at their level of abstraction. However, if you are interested in the underlying mechanisms and why these keywords may make a performance difference, at least in the case of `struct`s, then you could start with this [_Wikipedia article_][calling-conventions], noting that C# uses `stdcall` on x86/64. + +The essence of the story is that in the case of unmodified parameters the **value** of a variable is copied onto the program's stack to make it available to a called routine whereas for `ref`, `out` and `in` parameters a pointer (**reference**) to the memory containing the value is placed on the program's stack and values are assigned to the memory pointed at by the reference. + +[passing-parameters]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters +[ref-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference +[in-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier +[out-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier +[discard]: https://docs.microsoft.com/en-us/dotnet/csharp/discards +[calling-conventions]: https://en.wikipedia.org/wiki/X86_calling_conventions +[so-java-parameters]: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value +[ref-local]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-locals +[ref-return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values +[so-tuples-vs-out]: https://stackoverflow.com/questions/6381918/returning-two-values-tuple-vs-out-vs-struct diff --git a/exercises/concept/parameters/.docs/hints.md b/exercises/concept/parameters/.docs/hints.md new file mode 100644 index 0000000000..910df616a9 --- /dev/null +++ b/exercises/concept/parameters/.docs/hints.md @@ -0,0 +1,17 @@ +## General + +- [passing-parameters][passing-parameters]: explains how values can be passed as arguments. +- [ref-parameter][ref-parameter]: describes how `ref` parameters work. +- [out-parameter][out-parameter]: describes how `out` parameters work. + +## 1. Enable the remote control car to display sponsor names + +This [article][passing-parameters] discusses how to implement a method which takes a variable number of arguments. + +## 2 Get the car's telemetry data + +To perform this task you need to know how to deal with both [out][out-parameter] and [ref][ref-parameter] parameters. + +[passing-parameters]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-references/passing-parameters +[ref-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference +[out-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier diff --git a/exercises/concept/parameters/.docs/instructions.md b/exercises/concept/parameters/.docs/instructions.md new file mode 100644 index 0000000000..0f6ec12358 --- /dev/null +++ b/exercises/concept/parameters/.docs/instructions.md @@ -0,0 +1,62 @@ +The remote control car project you kicked off in the `classes` exercise has gone well (congratulations!) and due to a number of recent sponsorship deals there is money in the budget for enhancements. + +Part of the budget is being used to provide some telemetry. + +To keep the sponsors sweet a panel has been installed on the car to display the sponsors names as it goes round the track. + +You will note that the introduction of these fancy new technologies has dramatically reduced the car's battery life. + +## 1. Enable the remote control car to display sponsor names + +Implement `SetSponsors()` to take one or more sponsor names and store them on the car. + +Note that the `SetSponsors()` method's argument is guaranteed to be non-null. + +Implement `DisplaySponsor()` to display the selected sponsor. The first sponsor passed in has a `sponsorNum` of 0, the second, 1 etc. + +```csharp +var car = RemoteControlCar.Buy(); +car.SetSponsors("Exercism", "Walker Industries", "Acme Co."); +var sp2 = car.DisplaySponsor(sponsorNum: 1); +// => "Walker Industries" +``` + +## 2 Get the car's telemetry data + +Implement the `RemoteControlCar.GetTelemetryData()` method. + +`GetTelemetryData()` should make the battery percentage and distance driven in meters available via `out` parameters. + +`GetTelementryData()` should return `false` if the serialNum argument is less than the previously received value. (There is some issue of multiple telemetry nodes being involved). In this case `serialNum` will be set to the highest previous `serialNum` and battery percentage and meters driven will both be set to `-1`. Where the call is successful `serialNum` remains unchanged. + +```csharp +var car = RemoteControlCar.Buy(); +car.Drive(); +car.Drive(); +int serialNum = 0; +car.GetTelemetryData(ref serialNum, out int batteryPercentage, out int distanceDrivenInMeters); +// => true, 4L, 80, 4 + +serialNum = 1; +car.GetTelemetryData(ref serialNum, out batteryPercentage, out distanceDrivenInMeters); +// => false, 4L, -1, -1 +``` + +## 3 Add functionality so that the telemetry system can get battery usage per meter + +Implement the `TelemetryClient.GetBatteryUsagePerMeter()` method. + +This will call `RemoteControlCar.GetTelemetryData()`. If `GetTelemetryData()` returns `false` then this routine should return "no data". If `GetTelemetryData()` returns `true` then a message in the following form should be returned ""usage-per-meter= "usage-per-meter=5" + +serialNum = 4; +tc.GetBatteryUsagePerMeter(serialNum); +// => "no data" +``` diff --git a/exercises/concept/parameters/.docs/introduction.md b/exercises/concept/parameters/.docs/introduction.md new file mode 100644 index 0000000000..1c42283f86 --- /dev/null +++ b/exercises/concept/parameters/.docs/introduction.md @@ -0,0 +1,47 @@ +This exercise discusses some details of method parameters and their use in C#. + +Parameters convey information from a calling method to a called method. + +- The behavior of parameters can be modified by the use of modifies such as `ref` and `out`. + +- A parameter with the `out` modifier conveys a value back from the called method to the caller. The parameter can be passed to the called method without being initialized and in any case it is treated within the called method as if, on entry, it had not been initialized. An understanding of the behavior and rules regarding parameter modifiers can be gained most easily through examples (see below) and compiler messages. + +```csharp +void Foo(out int val) +{ + val = 42; +} +void Bar(int val) +{ + val = 42; +} + +int importantValue = 1729; +Foo(out importantValue); +var result = importantValue == 42; +// => true + +importantValue = 1729; +Bar(importantValue); +result = importantValue == 1729; +// => true +``` + +- `out` parameters must be assigned to within a called method. + +- A parameter with the `ref` modifier passes a value into a called method. When the method returns the caller will find any updates made by the called method in that parameter. + +```csharp +void Foo(ref int val) +{ + val *= 7; +} + +int importantValue = 6; +Foo(ref importantValue); +return importantValue; +// => 42 +``` + +- `ref` parameters must be variables as the called method will be operating directly on the parameter as seen by the caller. +- The `out` and `ref` modifiers are required both in the called method signature and at the call site. diff --git a/exercises/concept/parameters/.meta/Example.cs b/exercises/concept/parameters/.meta/Example.cs new file mode 100644 index 0000000000..0e0c8ea3a6 --- /dev/null +++ b/exercises/concept/parameters/.meta/Example.cs @@ -0,0 +1,78 @@ +using System; + + +public class RemoteControlCar +{ + private int batteryPercentage = 100; + private int distanceDrivenInMeters = 0; + private string[] sponsors = new string[0]; + private int latestSerialNum = 0; + + public void Drive() + { + if (batteryPercentage > 0) + { + batteryPercentage -= 10; + distanceDrivenInMeters += 2; + } + } + + public void SetSponsors(params string[] sponsors) + { + this.sponsors = sponsors; + } + + public string DisplaySponsor(int sponsorNum) + { + return sponsors[sponsorNum]; + } + + public bool GetTelemetryData(ref int serialNum, + out int batteryPercentage, out int distanceDrivenInMeters) + { + if (serialNum > latestSerialNum) + { + latestSerialNum = serialNum; + batteryPercentage = this.batteryPercentage; + distanceDrivenInMeters = this.distanceDrivenInMeters; + return true; + } + else + { + serialNum = latestSerialNum; + batteryPercentage = -1; + distanceDrivenInMeters = -1; + return false; + } + } + + public static RemoteControlCar Buy() + { + return new RemoteControlCar(); + } +} + +public class TelemetryClient +{ + private RemoteControlCar car; + + public TelemetryClient(RemoteControlCar car) + { + this.car = car; + } + + public string GetBatteryUsagePerMeter(int serialNum) + { + int localSerialNum = serialNum; + bool goodData = car.GetTelemetryData(ref localSerialNum, + out int batteryPercentage, out int distanceDrivenInMeters); + + if (!goodData || distanceDrivenInMeters == 0) + { + return "no data"; + } + + return "usage-per-meter=" + (100 - batteryPercentage) / distanceDrivenInMeters; + } +} + diff --git a/exercises/concept/parameters/.meta/config.json b/exercises/concept/parameters/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/parameters/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/parameters/.meta/design.md new file mode 100644 index 0000000000..edd56ea42f --- /dev/null +++ b/exercises/concept/parameters/.meta/design.md @@ -0,0 +1,27 @@ +## Learning objectives + +- Know the difference between value and reference type parameters. +- Know how to pass value types by reference using the `ref` and `out` modifiers. + +## Out of scope + +- Overload resolution. +- ref returns. +- ref locals. +- `in` modifier + +## Concepts + +This Concepts Exercise's Concepts are: + +- `parameters`: know the difference between value and reference type parameters; know how to pass value types by reference using the `ref` and `out` modifiers. + +## Prequisites + +This Concept Exercise's prerequisites Concepts are: + +- `conditionals`: `if`, `else` +- `numbers` +- `strings` +- `constructors`: the exercise provides a gentle intuitive introduction to simple parameters +- `named-parameters`: introduced in the `method-overloading` exercise and used here in _instructions.md_. diff --git a/exercises/concept/parameters/Parameters.cs b/exercises/concept/parameters/Parameters.cs new file mode 100644 index 0000000000..113590d37b --- /dev/null +++ b/exercises/concept/parameters/Parameters.cs @@ -0,0 +1,54 @@ +using System; + +public class RemoteControlCar +{ + private int batteryPercentage = 100; + private int distanceDrivenInMeters = 0; + private string[] sponsors = new string[0]; + private int latestSerialNum = 0; + + public void Drive() + { + if (batteryPercentage > 0) + { + batteryPercentage -= 10; + distanceDrivenInMeters += 2; + } + } + + public void SetSponsors(params string[] sponsors) + { + throw new NotImplementedException("Please implement the RemoteControlCar.SetSponsors() method"); + } + + public string DisplaySponsor(int sponsorNum) + { + throw new NotImplementedException("Please implement the RemoteControlCar.DisplaySponsor() method"); + } + + public bool GetTelemetryData(ref int serialNum, + out int batteryPercentage, out int distanceDrivenInMeters) + { + throw new NotImplementedException("Please implement the RemoteControlCar.GetTelemetryData() method"); + } + + public static RemoteControlCar Buy() + { + return new RemoteControlCar(); + } +} + +public class TelemetryClient +{ + private RemoteControlCar car; + + public TelemetryClient(RemoteControlCar car) + { + this.car = car; + } + + public string GetBatteryUsagePerMeter(int serialNum) + { + throw new NotImplementedException("Please implement the TelemetryClient.GetBatteryUsagePerMeter() method"); + } +} diff --git a/exercises/concept/parameters/Parameters.csproj b/exercises/concept/parameters/Parameters.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/parameters/Parameters.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/parameters/ParametersTests.cs b/exercises/concept/parameters/ParametersTests.cs new file mode 100644 index 0000000000..060f0feec1 --- /dev/null +++ b/exercises/concept/parameters/ParametersTests.cs @@ -0,0 +1,57 @@ +using Xunit; + +public class ParametersTests +{ + [Fact] + public void DisplayNextSponsor_for_3_sponsors() + { + var car = RemoteControlCar.Buy(); + car.SetSponsors("Exercism", "Walker Industries", "Acme Co."); + var sp1 = car.DisplaySponsor(sponsorNum: 0); + var sp2 = car.DisplaySponsor(sponsorNum: 1); + var sp3 = car.DisplaySponsor(sponsorNum: 2); + Assert.Equal((sp1, sp2, sp3), ("Exercism", "Walker Industries", "Acme Co.")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetTelmetryData_good() + { + var car = RemoteControlCar.Buy(); + car.Drive(); + car.Drive(); + int serialNum = 1; + car.GetTelemetryData(ref serialNum, out int batteryPercentage, out int distanceDrivenInMeters); + Assert.Equal((1, 80, 4), (serialNum, batteryPercentage, distanceDrivenInMeters)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetTelmetryData_bad() + { + var car = RemoteControlCar.Buy(); + int batteryPercentage, distanceDrivenInMeters; + car.Drive(); + car.Drive(); + int serialNum = 4; + car.GetTelemetryData(ref serialNum, out batteryPercentage, out distanceDrivenInMeters); + serialNum = 1; + car.GetTelemetryData(ref serialNum, out batteryPercentage, out distanceDrivenInMeters); + Assert.Equal((4, -1, -1), (serialNum, batteryPercentage, distanceDrivenInMeters)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetUsagePerMeter_good() + { + var car = RemoteControlCar.Buy(); + car.Drive(); car.Drive(); + var tc = new TelemetryClient(car); + Assert.Equal("usage-per-meter=5", tc.GetBatteryUsagePerMeter(serialNum: 1)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetUsagePerMeter_not_started() + { + var car = RemoteControlCar.Buy(); + var tc = new TelemetryClient(car); + Assert.Equal("no data", tc.GetBatteryUsagePerMeter(serialNum: 1)); + } +} From 0f84eb68faefbd578a998f8f73f9d1d566e282e9 Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 1 Jul 2020 02:26:54 -0400 Subject: [PATCH 161/327] added color to after.md on chars * added color to after.md on chars * [CI] Format code Co-authored-by: github-actions[bot] --- exercises/concept/chars/.docs/after.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/exercises/concept/chars/.docs/after.md b/exercises/concept/chars/.docs/after.md index 9a75061180..f6f788a8e3 100644 --- a/exercises/concept/chars/.docs/after.md +++ b/exercises/concept/chars/.docs/after.md @@ -69,7 +69,7 @@ Obviously there is no equivalence between a `byte` at 8 bits and the 16 bit `cha Using `StringBuilder` is seen as hugely preferable to building up strings with multiple repeated concatenations with a `+` or `+=` operator. Obviously simple one off concatenations are preferable -to instantiating a `StringBuilder` for clarity as well as performance. +to instantiating a `StringBuilder` for clarity as well as performance. [This][skeet-stringbuilder] is what [Jon Skeet][so-jon-skeet] has to say about performance. [chars-docs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char [chars-tutorial]: https://csharp.net-tutorials.com/data-types/the-char-type/ @@ -87,3 +87,5 @@ to instantiating a `StringBuilder` for clarity as well as performance. [is-digit]: https://docs.microsoft.com/en-us/dotnet/api/system.char.isdigit?view=netcore-3.1 [get-next-text-element]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo.getnexttextelement?view=netcore-3.1 [compare-to]: https://docs.microsoft.com/en-us/dotnet/api/system.char.compareto?view=netcore-3.1 +[skeet-stringbuilder]: https://jonskeet.uk/csharp/stringbuilder.html +[so-jon-skeet]: https://stackoverflow.com/users/22656/jon-skeet From 09d80d3db2a101dd4c478dba6594fb5019364b2c Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 1 Jul 2020 08:11:06 -0400 Subject: [PATCH 162/327] object-initializers new concept exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * object-initialization initial commit * object-initialization rough and ready review for initial consideration * object-initialization WIP * object-initialization complete-ish for draft PR * object-initialization proofed-ish for draft PR * [CI] Format code * object-initialization cosmatic * object-initializers draft PR review points * object-initializers draft PR review points * object-initializers proofing * object-initializers proofing * object-initializers proofing * object-initializers proofing * object-initializers proofing * object-initializers track config updated * Apply suggestions from code review Co-authored-by: Erik Schierboom * time ready for draft PR * time ready for draft PR Co-authored-by: Erik Schierboom Co-authored-by: github-actions[bot] --- .../object-initializers/.docs/after.md | 41 +++++++++++++ .../object-initializers/.docs/hints.md | 15 +++++ .../object-initializers/.docs/instructions.md | 38 +++++++++++++ .../object-initializers/.docs/introduction.md | 27 +++++++++ .../object-initializers/.meta/Example.cs | 57 +++++++++++++++++++ .../object-initializers/.meta/config.json | 8 +++ .../object-initializers/.meta/design.md | 18 ++++++ .../ObjectInitialization.cs | 26 +++++++++ .../ObjectInitialization.csproj | 13 +++++ .../ObjectInitializationTests.cs | 49 ++++++++++++++++ 10 files changed, 292 insertions(+) create mode 100644 exercises/concept/object-initializers/.docs/after.md create mode 100644 exercises/concept/object-initializers/.docs/hints.md create mode 100644 exercises/concept/object-initializers/.docs/instructions.md create mode 100644 exercises/concept/object-initializers/.docs/introduction.md create mode 100644 exercises/concept/object-initializers/.meta/Example.cs create mode 100644 exercises/concept/object-initializers/.meta/config.json create mode 100644 exercises/concept/object-initializers/.meta/design.md create mode 100644 exercises/concept/object-initializers/ObjectInitialization.cs create mode 100644 exercises/concept/object-initializers/ObjectInitialization.csproj create mode 100644 exercises/concept/object-initializers/ObjectInitializationTests.cs diff --git a/exercises/concept/object-initializers/.docs/after.md b/exercises/concept/object-initializers/.docs/after.md new file mode 100644 index 0000000000..248bf7f518 --- /dev/null +++ b/exercises/concept/object-initializers/.docs/after.md @@ -0,0 +1,41 @@ +Object initializers are an alternative to constructors. The syntax is a comma separated list of field name=value pairs, illustrated below: + +```csharp +public class Person +{ + public string Name; + public string Address; +} + +var person = new Person{Name="The President", Address = "Élysée Palace"}; +``` + +Collections can also be initialized in this way. Typically, this is accomplished with comma separated lists as shown here: + +```csharp +IList people = new List{ new Person(), new Person{Name="Joe Shmo"}}; +``` + +This approach (and syntax) can be used with any class that implements `IEnumerable` and has an `Add()` method. + +Fields can be listed in any order or ommitted completely. + +Dictionaries use the following syntax: + +```csharp +IDictionary numbers = new Dictionary{ [0] = "zero", [1] = "one"...}; + +// or + +IDictionary numbers = new Dictionary{ {0, "zero" }, {1, "one"}...}; +``` + +The initialized fields must be accessible to the caller. Typically, this means they must be `public` or `internal`. + +There is a strong trend promoting immutability amongst the language designers and leading practitioners, so the mutability of objects initialized in this way is seen as a disadvantage. There are proposals to introduce an `init` clause in the upcoming version of the language, C# 9, which may address this. + +- [object initializer][object-initializers] documentation describes how to use initialzers. +- [collection initializer][collection-initializers] documentation gives a preview of how initializers can be used with collections like dictionaries and lists. + +[object-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers +[collection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers diff --git a/exercises/concept/object-initializers/.docs/hints.md b/exercises/concept/object-initializers/.docs/hints.md new file mode 100644 index 0000000000..558b61e016 --- /dev/null +++ b/exercises/concept/object-initializers/.docs/hints.md @@ -0,0 +1,15 @@ +## General + +- [object initializer][object-initializers] documentation describes how to use initialzers. +- [collection initializer][collection-initializers] documentation gives a preview of how initializers can be used with collections like dictionaries and lists. + +## 1. Store the system admin's details hard-coded in the system and make it available to callers. + +- You can see the syntax for [object initializers][object-initializers] here. + +## 2 Store the developers' details hard-coded in the system and make them available in the form of a dictionary + +- You can see the syntax for [collection initializers][collection-initializers] here. + +[object-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers +[collection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers diff --git a/exercises/concept/object-initializers/.docs/instructions.md b/exercises/concept/object-initializers/.docs/instructions.md new file mode 100644 index 0000000000..3d9dfed23a --- /dev/null +++ b/exercises/concept/object-initializers/.docs/instructions.md @@ -0,0 +1,38 @@ +You've been asked to do some more work on the network authentication system. + +In addition to the admin identity being hard-coded in the system during development the powers that be also want senior developers to be given the same treatment. + +## 1. Store the system admin's details hard-coded in the system and make it available to callers. + +The admin's details are as follows: + +| Email | Eye Color | Philtrum Width | Name | Address 1 | Address 2 | +| ------------ | --------- | -------------- | -------- | --------- | --------- | +| admin@ex.ism | greeen | 0.9 | Chanakya | Mombai | India | + +Implement the `Authenticator.Admin` property to return the system admin's identity details. The name and each part of the address should be in a separate element of the `NameAndAddress` list. + +```csharp +var authenticator = new Authenticator(); +authenticator.Admin; +// => {"admin@ex.ism", {"green", 0.9m}, ["Chanakya", "Mombai", "India"]} +``` + +## 2 Store the developers' details hard-coded in the system and make them available in the form of a dictionary + +The developers' details are as follows: + +| Email | Eye Color | Philtrum Width | Name | Address 1 | Address 2 | +| ------------- | --------- | -------------- | -------- | --------- | --------- | +| bert@ex.ism | blue | 0.8 | Bertrand | Paris | France | +| anders@ex.ism | brown | 0.85 | Anders | Redmond | USA | + +Implement the `Authenticator.Developers()` method to return the developers' identity details. The dictionary key is the developer's name. + +```csharp +var authenticator = new Authenticator(); +authenticator.Developers; +// => {"bert" = {"bert@ex.ism", {"blue", 0.8m}, ["Bertrand", "Paris", "France"]}, +// ["anders" = {"bert@ex.ism", {"brown", 0.85m}, ["Anders", "Redmond", "USA"]}, + +``` diff --git a/exercises/concept/object-initializers/.docs/introduction.md b/exercises/concept/object-initializers/.docs/introduction.md new file mode 100644 index 0000000000..25b3b07ef5 --- /dev/null +++ b/exercises/concept/object-initializers/.docs/introduction.md @@ -0,0 +1,27 @@ +Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets: + +```csharp +public class Person +{ + public string Name; + public string Address; +} + +var person = new Person{Name="The President", Address = "Élysée Palace"}; +``` + +Collections can also be initialized in this way. Typically, this is accomplished with comma separated lists as shown here: + +```csharp +IList people = new List{ new Person(), new Person{Name="Joe Shmo"}}; +``` + +Dictinaries use the following syntax: + +```csharp +IDictionary numbers = new Dictionary{ [0] = "zero", [1] = "one"...}; + +// or + +IDictionary numbers = new Dictionary{ {0, "zero" }, {1, "one"}...}; +``` diff --git a/exercises/concept/object-initializers/.meta/Example.cs b/exercises/concept/object-initializers/.meta/Example.cs new file mode 100644 index 0000000000..27713e49b4 --- /dev/null +++ b/exercises/concept/object-initializers/.meta/Example.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +public class Authenticator +{ + public Identity Admin { get; } = new Identity + { + Email = "admin@ex.ism", + FacialFeatures = new FacialFeatures + { + EyeColor = "green", + PhiltrumWidth = 0.9m + }, + NameAndAddress = new List{"Chanakya", "Mombai", "India"} + }; + + public IDictionary Developers { get; } + = new Dictionary + { + ["Bertrand"] = new Identity + { + Email = "bert@ex.ism", + FacialFeatures = new FacialFeatures + { + EyeColor = "blue", + PhiltrumWidth = 0.8m + }, + NameAndAddress = new List{"Bertrand", "Paris", "France"} + }, + + ["Anders"] = new Identity + { + Email = "anders@ex.ism", + FacialFeatures = new FacialFeatures + { + EyeColor = "brown", + PhiltrumWidth = 0.85m + }, + NameAndAddress = new List{"Anders", "Redmond", "USA"} + } + }; +} + +//**** please do not modify the FacialFeatures class **** +public class FacialFeatures +{ + public string EyeColor { get; set; } + public decimal PhiltrumWidth { get; set; } +} + +//**** please do not modify the Identity class **** +public class Identity +{ + public string Email { get; set; } + public FacialFeatures FacialFeatures { get; set; } + public IList NameAndAddress { get; set; } +} diff --git a/exercises/concept/object-initializers/.meta/config.json b/exercises/concept/object-initializers/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/object-initializers/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/object-initializers/.meta/design.md b/exercises/concept/object-initializers/.meta/design.md new file mode 100644 index 0000000000..ea9642805e --- /dev/null +++ b/exercises/concept/object-initializers/.meta/design.md @@ -0,0 +1,18 @@ +## Learning objectives + +- Know how and when to user object initializers. +- Understand that object initializers are used with collections + +## Out of scope + +- Anonymous classes + +## Concepts + +- `object-initializers` + +## Prerequisites + +- `constructors` +- `properties` +- `dictionaries` diff --git a/exercises/concept/object-initializers/ObjectInitialization.cs b/exercises/concept/object-initializers/ObjectInitialization.cs new file mode 100644 index 0000000000..ce972f11ca --- /dev/null +++ b/exercises/concept/object-initializers/ObjectInitialization.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; + +public class Authenticator +{ + // TODO: Impleent the Authenticator.Admin property + public Identity Admin { get; } + + // TODO: Impleent the Authenticator.Developers property + public IDictionary Developers { get; } +} + +//**** please do not modify the FacialFeatures class **** +public class FacialFeatures +{ + public string EyeColor { get; set; } + public decimal PhiltrumWidth { get; set; } +} + +//**** please do not modify the Identity class **** +public class Identity +{ + public string Email { get; set; } + public FacialFeatures FacialFeatures { get; set; } + public IList NameAndAddress { get; set; } +} diff --git a/exercises/concept/object-initializers/ObjectInitialization.csproj b/exercises/concept/object-initializers/ObjectInitialization.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/object-initializers/ObjectInitialization.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/object-initializers/ObjectInitializationTests.cs b/exercises/concept/object-initializers/ObjectInitializationTests.cs new file mode 100644 index 0000000000..e58c5aa7c3 --- /dev/null +++ b/exercises/concept/object-initializers/ObjectInitializationTests.cs @@ -0,0 +1,49 @@ +using System; +using Xunit; + +public class ObjectInitializationTests +{ + [Fact] + public void GetAdmin() + { + var authenticator = new Authenticator(); + var admin = authenticator.Admin; + string[] actual = + { + admin?.Email, + admin?.FacialFeatures.EyeColor, + admin?.FacialFeatures.PhiltrumWidth.ToString(), + admin?.NameAndAddress[0] + }; + string[] expected = + { + "admin@ex.ism", + "green", + "0.9", + "Chanakya" + }; + Assert.Equal(expected, actual); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetDevelopers() + { + var authenticator = new Authenticator(); + var developers = authenticator.Developers; + string[] actual = + { + developers["Bertrand"]?.Email, + developers["Bertrand"]?.FacialFeatures.EyeColor, + developers["Anders"]?.FacialFeatures.PhiltrumWidth.ToString(), + developers["Anders"]?.NameAndAddress[1] + }; + string[] expected = + { + "bert@ex.ism", + "blue", + "0.85", + "Redmond" + }; + Assert.Equal(expected, actual); + } +} From acb9f6e85133268904dc8c58d46e35330af1e6d8 Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 1 Jul 2020 23:20:19 -0400 Subject: [PATCH 163/327] randomness - updated sets concept * randomness - updated sets concept * [CI] Format code Co-authored-by: github-actions[bot] --- exercises/concept/equality/.meta/design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/equality/.meta/design.md index e6f75e69fc..292c325dce 100644 --- a/exercises/concept/equality/.meta/design.md +++ b/exercises/concept/equality/.meta/design.md @@ -17,7 +17,7 @@ This Concepts Exercise's Concepts are: - `equality`: know how to check for equality and inequality; know how reference equality differs from structural equality; know that equality works by default for value and reference types; know how to customize equality checks using `Equals` and `GetHashCode()`; know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them. -- `sets`: hash sets as provided by C#/.NET. +- `sets`: Know how to use hash sets `HashSet` as provided by the .NET BCL. Understand the relationship with `Object.GetHashCode()` and the performance charateristics of hash sets. ## Prequisites From 95e4c01a3e235048c032372ec0d320718c5e75d5 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 3 Jul 2020 03:15:33 -0400 Subject: [PATCH 164/327] time new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * time pre-PR draft * time pre-PR draft * time WIP * time WIP * time WIP * time ready for draft PR * time ready for draft PR * [CI] Format code * Apply suggestions from code review Co-authored-by: Erik Schierboom * time review points from draft PR * time review points from draft PR * time review points from draft PR * time prep for final review * time prep for final review * time proofing * time added to track config * time proofed * time proofed * time cosmetic fix * resource-cleanup added cross-platform aspect to the puzzle * resource-cleanup added cross-platform aspect to the puzzle Co-authored-by: Erik Schierboom Co-authored-by: github-actions[bot] --- exercises/concept/time/.docs/after.md | 44 +++++ exercises/concept/time/.docs/hints.md | 32 ++++ exercises/concept/time/.docs/instructions.md | 73 ++++++++ exercises/concept/time/.docs/introduction.md | 7 + exercises/concept/time/.meta/Example.cs | 144 +++++++++++++++ exercises/concept/time/.meta/config.json | 8 + exercises/concept/time/.meta/design.md | 27 +++ exercises/concept/time/Time.cs | 44 +++++ exercises/concept/time/Time.csproj | 13 ++ exercises/concept/time/TimeTests.cs | 177 +++++++++++++++++++ 10 files changed, 569 insertions(+) create mode 100644 exercises/concept/time/.docs/after.md create mode 100644 exercises/concept/time/.docs/hints.md create mode 100644 exercises/concept/time/.docs/instructions.md create mode 100644 exercises/concept/time/.docs/introduction.md create mode 100644 exercises/concept/time/.meta/Example.cs create mode 100644 exercises/concept/time/.meta/config.json create mode 100644 exercises/concept/time/.meta/design.md create mode 100644 exercises/concept/time/Time.cs create mode 100644 exercises/concept/time/Time.csproj create mode 100644 exercises/concept/time/TimeTests.cs diff --git a/exercises/concept/time/.docs/after.md b/exercises/concept/time/.docs/after.md new file mode 100644 index 0000000000..a4fd522383 --- /dev/null +++ b/exercises/concept/time/.docs/after.md @@ -0,0 +1,44 @@ +Although this exercise investigates the concept of `time` in practice you rarely deal with times on their own. They are almost always dealt with in conjunction with dates. There is no specific separate _time_ type, only [`DateTime`][date-time]. + +Time-of-day can be expressed with [`TimeSpan`][time-span] (and this is in fact the return type of `DateTime.TimeOfDay`). It is not [purpose made][skeet-time-of-day] so the expressiveness of code can get a bit clunky. For instance, what do you expect time-of-day to be for an instance of `DateTime` that is in UTC form? But, it does the job. + +A discussion of _time_ has a number of facets: + +- local time vs. universal co-ordinated time (UTC) +- arithmetic on `DateTime` +- Time zones (including daylight saving time) +- Date-time string parsing and formatting. +- Resolution (timer selection etc.) + +This exercise covered local vs. UTC, date-time arithmetic, time-zones and date-time parsing. + +[Formatting][date-string-formatting] is discussed in the `string-formatting` exercise. + +Resolution and timers are [much discussed][so-timers] on the web. The `DateTime` API has specific routines to handle file timestamps. + +It's usually a good idea to store date-times long term in UTC form. This ensures consistency if more than one timezone is in play and this approach avoids potential problems with daylight saving. + +The disadvantage of UTC times is that they need to be converted to local times if time-of-day is a significant factor. + +For the most part `DateTime.ToUniversalTime()` and `DateTime.ToLocalTime()` work well as long as processing is based around the timezone of your computer. If multiple time zones are involved, or a different one to that of your computer then you will need the [`TimeZoneInfo`][time-zone-info] class to handle conversions. Not the obsolete ~~TimeZone~~ object. + +You will recall from the coding exercise that the all-important time zone identifiers differ between Windows and other platforms. This [article][cross-platform-time-zones] is a good introduction to this cross-platform issue. Note that `TimeZoneInfo.GetSystemTimeZones()` will list your platform's time zones. + +This [article][time-overview] is a good overview of time and timezones. + +For date time arithmetic, in the coding exercise, you may well have used the `TimeSpan` struct. When you need to do arithmetic involving whole months or years then the `DateTime` struct provides a number of methods such as `AddHours()` and `AddMonths()`. + +If dates and times are a pervasive and/or critical part of your project then you should investigate [Noda Time][noda-time] + +In case you were wondering, according to this [Wikipedia article][wiki-utc] the abbreviation for universal time, UTC, arose from a compromise between English (UCT) and French (CUT) speakers such that neither language would appear to take precedence. + +[so-timers]: https://stackoverflow.com/questions/10317088/why-there-are-5-versions-of-timer-classes-in-net +[cross-platform-time-zones]: https://devblogs.microsoft.com/dotnet/cross-platform-time-zones-with-net-core/ +[skeet-time-of-day]: https://stackoverflow.com/a/2037375/96167 +[time-overview]: https://docs.microsoft.com/en-us/dotnet/standard/datetime/ +[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 +[noda-time]: https://nodatime.org/ +[date-string-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-2.0 +[time-zone-info]: https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=netcore-2.0 +[wiki-utc]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time diff --git a/exercises/concept/time/.docs/hints.md b/exercises/concept/time/.docs/hints.md new file mode 100644 index 0000000000..6a20856000 --- /dev/null +++ b/exercises/concept/time/.docs/hints.md @@ -0,0 +1,32 @@ +## General + +- This [article][time-overview] is an overview of dates, times and time zones on .NET. +- The `DateTime` struct is documented [here][date-time]. + +## 1. Provide local time equivalents of UTC (Universal Coordinated Time) appointments for the administrators + +Look for a suitable `DateTime` member converting from UTC to local time. + +## 2. Schedule appointments in New York, London and Paris + +Use the [`TimeZoneInfo`][time-zone-info] class and select the appropriate time zone ids from the task instructions. Remember that Windows and OSX/Linux have different ids. + +The method [`RuntimeInformation.IsOSPlatform()`] is central to having code paths that target different operating systems. + +## 3. Provide alerts to clients at intervals before the appointment + +One approach is to use [`TimeSpan`][time-span] to perform arithmetic on times. + +## 4. If daylight savings has recently changed we send a message to clients reminding them. + +`TimeZoneInfo` has appropriate methods for this. + +## 5. Use the local date time format to enter appointments + +Have a look at `DateTime.Parse()` and [`CultureInfo`][culture-info]. + +[time-overview]: https://docs.microsoft.com/en-us/dotnet/standard/datetime/ +[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 +[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-2.0 +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-2.0 +[time-zone-info]: https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=netcore-2.0 diff --git a/exercises/concept/time/.docs/instructions.md b/exercises/concept/time/.docs/instructions.md new file mode 100644 index 0000000000..945ca2016c --- /dev/null +++ b/exercises/concept/time/.docs/instructions.md @@ -0,0 +1,73 @@ +In this exercise you are back in the world of salons (first introduced in the `datetimes` exercise). As with a number of your projects another of your clients has had great success and opened outlets in London and Paris in addition to their New York base. + +## 1. Provide local time equivalents of UTC (Universal Coordinated Time) appointments for the administrators + +Implement the static `Appointment.ShowLocalTime()` method that takes a UTC time and returns it as a local time + +```csharp +// For a student in NY +Appointment.ShowLocalTime(new DateTime(2030, 7, 25, 13, 45, 0)); +// => {2030, 7, 25, 8, 45, 0} +``` + +## 2. Schedule appointments in New York, London and Paris + +Salons are responsible for taking their own bookings. The time input is local to the location of the salon. For instance, if someone enters a time of 13:45 for the New York salon for an appointment, they would expect the client to turn up just after lunch. Similarly, if someone entered a time of 13:45 for the London salon they would also expect the client arrive just after lunch. + +It will help you to know the time zone id for New York, London and Paris. + +On Mac (OSX) and Linux these are: + +- New York - America/New_York +- London - Europe/London +- Paris - Europe/Paris + +On Windows, they are: + +- New York - Eastern Standard Time +- London - GMT Standard Time +- Paris - W. Europe Standard Time + +Implement the static `Appointment.Shedule()` overload which takes a location and time string and returns the UTC time of the appointment. + +The implementation of `Schedule()` will need to allow the code, once built, to be run on Linux, Windows and Mac. This is the first exercise where you need to be concerned about the operating system. It will be necessary to have separate code paths to accommodate the difference in the time zone ids as described above. + +The date-time strings input are guaranteed to be valid. + +```csharp +Appointment.Schedule("7/25/2030 13:45:00", Location.Paris); +// => {2030, 7, 25, 11, 45, 0} +``` + +## 3. Provide alerts to clients at intervals before the appointment + +Implement the static `Appointment.GetAlertTime()` to provide alerts at 1 day (early), 1 hour 45 minutes (standard) and 30 minutes (late) before the appointment. + +```csharp +Appointment.GetAlertTime(new DateTime(2030, 7, 25, 14, 45, 0), AlertLevel.Early); +// => {2030, 7, 24, 14, 45, 0} +``` + +## 4. If daylight savings has recently changed we send a message to clients reminding them. + +Implement the static `Appointment.HasDaylightSavingChanged()` to return `true` if the daylight savings has become active or inactive in the last 7 days. + +```csharp +Appointment.HasDaylightSavingChanged(new DateTime(2020, 3, 30, 14, 45, 0), Location.London); +// => true +``` + +## 5. Use the local date time format to enter appointments + +In order that appointments can be made in a format familiar to the local staff you have been tasked with creating an experimental routine to allow dates and times to be entered in the default format for the location of the salon. + +Implement the `Appointment.NormalizeDateTime()` method that takes a well-formed date-time string in an format appropriate to the location and converts it into a `DateTime` object. No attempt is made to convert the date-time to UTC. + +If a bad format is entered then a `DateTime` with a value of 1/1/1 should be returned. + +```csharp +Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.London); +// => {2020, 3, 30, 13, 45, 0} +Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.NewYork); +// => {1, 1, 1, 0, 0, 0} +``` diff --git a/exercises/concept/time/.docs/introduction.md b/exercises/concept/time/.docs/introduction.md new file mode 100644 index 0000000000..b77d0d4e7e --- /dev/null +++ b/exercises/concept/time/.docs/introduction.md @@ -0,0 +1,7 @@ +The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`. + +The `TimeZoneInfo` class provides routines for handling the differences between time zones. The `TimeZoneInfo` class also contains methods that facilitate dealing with daylight saving time. + +The `CultureInfo` class supports locale dependent date time formats. + +To support cross-platform coding the `RuntimeInformation` class allows you to detect which operating system your code is executing on, Linux, Windows or OSX. diff --git a/exercises/concept/time/.meta/Example.cs b/exercises/concept/time/.meta/Example.cs new file mode 100644 index 0000000000..338a2ef3fd --- /dev/null +++ b/exercises/concept/time/.meta/Example.cs @@ -0,0 +1,144 @@ +using System; +using System.Globalization; +using System.Runtime.InteropServices; + +public enum Location +{ + NewYork, + London, + Paris +} + +public enum AlertLevel +{ + Early, + Standard, + Late +} + +public static class Appointment +{ + public static DateTime ShowLocalTime(DateTime dtUtc) + { + return dtUtc.ToLocalTime(); + } + + public static DateTime Schedule(string appointmentDateDescription, Location location) + { + TimeZoneInfo tziLocation = TimeZoneInfo.FindSystemTimeZoneById(GetTimeZoneId(location)); + DateTime dtl = DateTime.Parse(appointmentDateDescription); + DateTime dtu = TimeZoneInfo.ConvertTimeToUtc(dtl, tziLocation); + return dtu; + } + + public static DateTime GetAlertTime(DateTime appointment, AlertLevel alertLevel) + { + TimeSpan noticePeriod = new TimeSpan(); + + switch (alertLevel) + { + case AlertLevel.Early: + noticePeriod = new TimeSpan(1, 0, 0, 0); + break; + case AlertLevel.Standard: + noticePeriod = new TimeSpan(1, 45, 0); + break; + case AlertLevel.Late: + noticePeriod = new TimeSpan(0, 30, 0); + break; + } + + return appointment - noticePeriod; + } + + public static bool HasDaylightSavingChanged(DateTime dt, Location location) + { + DateTime dtPrevious = dt.AddDays(-7); + string tzid = string.Empty; + TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById(GetTimeZoneId(location)); + return tzi.IsDaylightSavingTime(dtPrevious) != tzi.IsDaylightSavingTime(dt); + } + + public static DateTime NormalizeDateTime(string dtStr, Location location) + { + try + { + return DateTime.Parse(dtStr, LocationToCulture(location)); + } + catch (Exception) + { + return DateTime.MinValue; + } + } + + private static CultureInfo LocationToCulture(Location location) + { + string cultureId = string.Empty; + switch (location) + { + case Location.NewYork: + cultureId = "en-US"; + break; + case Location.London: + cultureId = "en-GB"; + break; + case Location.Paris: + cultureId = "fr-FR"; + break; + } + return new CultureInfo(cultureId); + } + + private static string GetTimeZoneId(Location location) + { + if (IsWindows()) + { + return GetTimeZoneIdForWindows(location); + } + else + { + return GetTimeZoneIdForPosix(location); + } + } + + private static string GetTimeZoneIdForWindows(Location location) + { + string timeZoneId = string.Empty; + switch (location) + { + case Location.NewYork: + timeZoneId = "Eastern Standard Time"; + break; + case Location.London: + timeZoneId = "GMT Standard Time"; + break; + case Location.Paris: + timeZoneId = "W. Europe Standard Time"; + break; + } + return timeZoneId; + } + + private static string GetTimeZoneIdForPosix(Location location) + { + string timeZoneId = string.Empty; + switch (location) + { + case Location.NewYork: + timeZoneId = "America/New_York"; + break; + case Location.London: + timeZoneId = "Europe/London"; + break; + case Location.Paris: + timeZoneId = "Europe/Paris"; + break; + } + return timeZoneId; + } + + private static bool IsWindows() + { + return RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + } +} diff --git a/exercises/concept/time/.meta/config.json b/exercises/concept/time/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/time/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/time/.meta/design.md b/exercises/concept/time/.meta/design.md new file mode 100644 index 0000000000..b4a27456dd --- /dev/null +++ b/exercises/concept/time/.meta/design.md @@ -0,0 +1,27 @@ +## Learning objectives + +- Know how to use `time` in C#. +- Know how to get the current time. +- Know how to perform arithmetic on times. +- Know the difference between local time and UTC. + +## Out of scope + +- custom time zones +- [Noda Time][noda-time] +- We are not exercising student's ability to code a cross-platform solution. + +## Concepts + +- `time`: Know how to use `DateTime` when time-of-day is important. Understand the difference between local time and Universal Coordinated Time). Understand the role of `CultureInfo` in parsing times. Understand arithmetic with `DateTime`s. +- `timezone`: Know about time zones and their ids. Be familiar with cross-platform issues. Know how to convert dates and times between time zones. Know how to detect daylight saving time. +- `cross-platform`: know how to have different code paths (selected at run-time) for Linux, Windows and Mac + +## Prerequisites + +- `datetime` +- `switch-statements` +- `strings` +- `conditionals-if` + +[noda-time]: https://nodatime.org/ diff --git a/exercises/concept/time/Time.cs b/exercises/concept/time/Time.cs new file mode 100644 index 0000000000..8e2d5bbd8c --- /dev/null +++ b/exercises/concept/time/Time.cs @@ -0,0 +1,44 @@ +using System; + + +public enum Location +{ + NewYork, + London, + Paris +} + +public enum AlertLevel +{ + Early, + Standard, + Late +} + +public static class Appointment +{ + public static DateTime ShowLocalTime(DateTime dtUtc) + { + throw new NotImplementedException("Please implement the (static) Appointment.ShowLocalTime() method"); + } + + public static DateTime Schedule(string appointmentDateDescription, Location location) + { + throw new NotImplementedException("Please implement the (static) Appointment.Schedule() method"); + } + + public static DateTime GetAlertTime(DateTime appointment, AlertLevel alertLevel) + { + throw new NotImplementedException("Please implement the (static) Appointment.GetAlertTime() method"); + } + + public static bool HasDaylightSavingChanged(DateTime dt, Location location) + { + throw new NotImplementedException("Please implement the (static) Appointment.HasDaylightSavingChanged() method"); + } + + public static DateTime NormalizeDateTime(string dtStr, Location location) + { + throw new NotImplementedException("Please implement the (static) Appointment.NormalizeDateTime() method"); + } +} diff --git a/exercises/concept/time/Time.csproj b/exercises/concept/time/Time.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/time/Time.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/time/TimeTests.cs b/exercises/concept/time/TimeTests.cs new file mode 100644 index 0000000000..6ac57e3d67 --- /dev/null +++ b/exercises/concept/time/TimeTests.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using Xunit; + +public class TimeTests +{ + public TimeTests() + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US"); + } + + [Fact] + public void ShowLocalTime() + { + var dt = new DateTime(2030, 07, 25, 13, 45, 0); + var tzi = TimeZoneInfo.Local; + var offset = tzi.GetUtcOffset(dt); + Assert.Equal(dt + offset, Appointment.ShowLocalTime(dt)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Schedule_newyork() + { + Assert.Equal(new DateTime(2019, 07, 25, 12, 45, 0), + Appointment.Schedule("7/25/2019 08:45:00", Location.NewYork)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Schedule_london() + { + Assert.Equal(new DateTime(2019, 07, 25, 12, 45, 0), + Appointment.Schedule("7/25/2019 13:45:00", Location.London)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Schedule_paris() + { + Assert.Equal(new DateTime(2019, 07, 25, 12, 45, 0), + Appointment.Schedule("7/25/2019 14:45:00", Location.Paris)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetAlertTime_early() + { + Assert.Equal(new DateTime(2019, 07, 24, 16, 0, 0), + Appointment.GetAlertTime(new DateTime(2019, 7, 25, 16, 0, 0), + AlertLevel.Early)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetAlertTime_standard() + { + Assert.Equal(new DateTime(2019, 07, 25, 14, 15, 0), + Appointment.GetAlertTime(new DateTime(2019, 7, 25, 16, 0, 0), + AlertLevel.Standard)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetAlertTime_late() + { + Assert.Equal(new DateTime(2019, 07, 25, 15, 30, 0), + Appointment.GetAlertTime(new DateTime(2019, 7, 25, 16, 0, 0), + AlertLevel.Late)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_newyork_active() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 3, 13, 0, 0, 0), + Location.NewYork)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_newyork_inactive() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 11, 7, 0, 0, 0), + Location.NewYork)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_newyork_no_change() + { + Assert.False( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 12, 25, 0, 0, 0), + Location.NewYork)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_london_active() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 4, 1, 0, 0, 0), + Location.London)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_london_inactive() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 10, 29, 0, 0, 0), + Location.London)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_london_no_change() + { + Assert.False( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 12, 25, 0, 0, 0), + Location.London)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_paris_active() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 4, 1, 0, 0, 0), + Location.Paris)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_paris_inactive() + { + Assert.True( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 10, 29, 0, 0, 0), + Location.Paris)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DalylightSavingChanged_paris_no_change() + { + Assert.False( + Appointment.HasDaylightSavingChanged(new DateTime(2019, 12, 25, 0, 0, 0), + Location.Paris)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NormalizeDateTime_newyork() + { + Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Appointment.NormalizeDateTime("11/25/2019 13:45:00", + Location.NewYork)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NormalizeDateTime_london() + { + Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Appointment.NormalizeDateTime("25/11/2019 13:45:00", + Location.London)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NormalizeDateTime_paris() + { + Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Appointment.NormalizeDateTime("25/11/2019 13:45:00", + Location.Paris)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void NormalizeDateTime_bad() + { + Assert.Equal( DateTime.MinValue, + Appointment.NormalizeDateTime("25/11/2019 13:45:00", + Location.NewYork)); + } + + private static IList GetTimeZoneIds() + { + return TimeZoneInfo.GetSystemTimeZones().Select(tzi => tzi.Id).OrderBy(tzi => tzi).ToList(); + } +} From 66a42d3c876614c0a75994569f78069e1c28ba64 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 3 Jul 2020 03:27:12 -0400 Subject: [PATCH 165/327] resource-cleanup new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * resource-cleanup initial commit * resource-cleanup rough implementation for pre-PR discussion * removed template files * resource-cleanup WIP * resource-cleanup ready for draft PR * resource-cleanup ready for draft PR * resource-cleanup ready for draft PR * resource-cleanup ready for draft PR * [CI] Format code * Apply suggestions from code review Co-authored-by: Erik Schierboom * string-formatting - fix copy paste error * Update languages/exercises/concept/resource-cleanup/ResourceCleanupTests.cs Co-authored-by: Erik Schierboom * Update ResourceCleanupTests.cs * resource-cleanup prep for final PR * resource-cleanup prep for final PR * resource-cleanup prep for final PR * resource-cleanup prep for final PR * resource-cleanup prep for final PR * resource-cleanup track config.json updated Co-authored-by: Erik Schierboom Co-authored-by: github-actions[bot] --- .../concept/resource-cleanup/.docs/after.md | 70 +++++++++ .../concept/resource-cleanup/.docs/hints.md | 14 ++ .../resource-cleanup/.docs/instructions.md | 66 +++++++++ .../resource-cleanup/.docs/introduction.md | 1 + .../concept/resource-cleanup/.meta/Example.cs | 55 ++++++++ .../resource-cleanup/.meta/config.json | 8 ++ .../concept/resource-cleanup/.meta/design.md | 18 +++ .../resource-cleanup/ResourceCleanup.cs | 26 ++++ .../resource-cleanup/ResourceCleanup.csproj | 13 ++ .../resource-cleanup/ResourceCleanupTests.cs | 133 ++++++++++++++++++ 10 files changed, 404 insertions(+) create mode 100644 exercises/concept/resource-cleanup/.docs/after.md create mode 100644 exercises/concept/resource-cleanup/.docs/hints.md create mode 100644 exercises/concept/resource-cleanup/.docs/instructions.md create mode 100644 exercises/concept/resource-cleanup/.docs/introduction.md create mode 100644 exercises/concept/resource-cleanup/.meta/Example.cs create mode 100644 exercises/concept/resource-cleanup/.meta/config.json create mode 100644 exercises/concept/resource-cleanup/.meta/design.md create mode 100644 exercises/concept/resource-cleanup/ResourceCleanup.cs create mode 100644 exercises/concept/resource-cleanup/ResourceCleanup.csproj create mode 100644 exercises/concept/resource-cleanup/ResourceCleanupTests.cs diff --git a/exercises/concept/resource-cleanup/.docs/after.md b/exercises/concept/resource-cleanup/.docs/after.md new file mode 100644 index 0000000000..a1ed529cce --- /dev/null +++ b/exercises/concept/resource-cleanup/.docs/after.md @@ -0,0 +1,70 @@ +The [`IDisposable`][idisposable] interface is central to resource cleanup and has two significant roles in C#: + +- It indicates to users of the implementing class that they are responsible for letting the class know (by calling the [`Dispose()`][dispose] method) that it is no longer required so that it can release any unmanaged resources or reset its internal state as appropriate. This contrasts with the normal approach to cleaning up of allowing the [garbage collector][garbage-collector] to clean everything up (principally, release memory). +- In conjunction with the compiler and runtime the `IDisposable` interface supports the [`using` statement][using-statement] discussed in the `resource-lifetime` exercise. + +It is possible but unlikely that `Dispose()` will be called through the interface in some sort of generic cleanup routine. + +`IDisposable` is most commonly encountered with library classes that wrap operating system (unmanaged) resources such as [`System.IO.Stream`][stream] and [`System.IO.TextReader`][text-reader]. (`Stream`s and `TextReader`s are covered in other exercises). + +```csharp +public class TextHandler : IDispoable +{ + private TextReader reader = new TextReader(...); + + public void Dispose() + { + reader.Dispose(); + } +} +``` + +If a class you are using implements the `IDispoable` interface then you must ensure that `Dispose()` is called (by use of [`catch` and `finally`][try-catch-finally] clauses) when the instance is no longer required. If a class has a member which implements `IDisposable` then it may well need to implement `IDisposable` itself so that `Dispose()` can be called to dispose of the `IDisposble`-implementing member. + +```csharp +public class Activity : IDisposable +{ + private MyResource myResource; + + public Activity() + { + myResource = new MyResource(); + } + + public void Perform() + { + try + { + myResource.BeUseful(); + } + catch (Exception) + { + myResource.Dispose(); + } + } + + public void Dispose() + { + myResource.Dispose(); + } +} +``` + +The `IDisposable` interface may be useful even where no unmanaged resources are in the mix. Say you have a long-lived object which requires short-lived objects to register themselves with it and then unregister when they are no longer required. Implementing `IDisposable` on the short-lived object puts a developer using that class on notice that `Dispose()` needs to be called at the end of the short-lived object's life. + +#### Dispose pattern + +You will see references in the documentation to the [dispose pattern][dispose-pattern]. The _dispose pattern_ includes calling `Dispose()` from a class's [finalizer][finalizer] and ensuring that disposal of resources in base classes is handled correctly. The _dispose pattern_ is dealt with in a later exercise. + +The _dispose pattern_ mostly relates to unmanaged resources. If you are using [P/Inovke mechanism][native-interoperability] and `extern` methods then you need to understand how and when to implement the dispose pattern. Most C# developers rarely have to deal directly with unmanaged resources in this way. + +[finalizer]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[idisposable]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netcore-3.1 +[dispose]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?view=netcore-3.1 +[stream]: https://docs.microsoft.com/en-us/dotnet/api/system.io.stream?view=netcore-3.1 +[text-reader]: https://docs.microsoft.com/en-us/dotnet/api/system.io.textreader?view=netcore-3.1 +[native-interoperability]: https://docs.microsoft.com/en-us/dotnet/standard/native-interop/ +[dispose-pattern]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose +[garbage-collector]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals +[try-catch-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch-finally diff --git a/exercises/concept/resource-cleanup/.docs/hints.md b/exercises/concept/resource-cleanup/.docs/hints.md new file mode 100644 index 0000000000..d291934fe0 --- /dev/null +++ b/exercises/concept/resource-cleanup/.docs/hints.md @@ -0,0 +1,14 @@ +## General + +Documentation related to `IDisposable` is [here][idisposable] + +## 2. Write some data to the database + +[`try`/`catch`][try-catch-finally] is necessary to ensure that the database is restored to its `Closed` state if an exception is thrown because of bad data. + +## 3. Commit previously written data to the database + +[`try`/`catch`][try-catch-finally] is necessary to ensure that the database is restored to its `Closed` state if an exception is thrown because of bad data. + +[idisposable]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netcore-3.1 +[try-catch-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch-finally diff --git a/exercises/concept/resource-cleanup/.docs/instructions.md b/exercises/concept/resource-cleanup/.docs/instructions.md new file mode 100644 index 0000000000..e088b6fa79 --- /dev/null +++ b/exercises/concept/resource-cleanup/.docs/instructions.md @@ -0,0 +1,66 @@ +You are implementing an ORM (Object Relational Mapping) system over a database which has been provided by another team. + +The database is capable of handling a single transaction at one time. + +No logging or other error handling is required at this stage. + +Note that, internally, the database transitions through a number of state: Closed, TransactionStarted, DataWritten, Invalid, Closed. You can rely on the fact that the database is in a `Closed` state at the start of each exercise. + +The database has the following instance methods: + +- `Database.BeginTransaction()` starts a transaction on the database. If this is called when the database is not in a `Closed` state then an exception is thrown. If successful the internal state of the database will change to `TransactionStarted`. +- `Database.Write(string data)` writes data to the database within the transaction. If it receives bad data an exception will be thrown. An attempt to call this method without `BeginTransction()` having been called will cause an exception to be thrown. If successful the internal state of the database will change to `DataWritten`. +- `Database.Commit()` commits the transaction to the database. It may throw an exception if it can't close the transaction of if `Database.BeginTransaction()` had not been called. +- A call to`Databse.Dispose()` will clean up the database if an exception is thrown during a transaction. This will change the state of the database to `Closed`. + +## 1. Begin a transaction + +Implement `Orm.Begin()` to start a transaction on the database. If the database does not start with an internal state of `State.Closed` then it throws an `InvalidOperationException`. + +```csharp +var orm = new Orm(new Database()); +orm.Begin(); +// => database has an internal state of State.TransactionStarted +``` + +## 2. Write some data to the database + +Implement `Orm.Write()` to write some data to the database. If the database does not start with an internal state of `State.TransactionStarted` or bad data is written then an `InvalidOperationException` is thrown. If the write fails then the `Orm` must clean up the database. + +```csharp +var orm = new Orm(new Database()); +orm.Begin(); +orm.Write("some data"); +// => database has an internal state of State.DataWritten +orm.Write("bad write"); +// => database has an internal state of State.Closed +``` + +## 3. Commit previously written data to the database + +Implement `Orm.Commit()` to commit the data. If the commit fails then clean up the database. If the database does not start with an internal state of `State.DataWritten` then an `InvalidOperationException` is thrown. + +```csharp +var orm = new Orm(new Database()); +orm.Begin(); +orm.Write("some data"); +orm.Commit(); +// => database has an internal state of State.Closed +orm.Begin(); +orm.Write("bad commit"); +orm.Commit(); +// => database has an internal state of State.Closed +``` + +## 4. Ensure that the database is cleaned up correctly if the ORM has to close part way through a transaction. + +Implement the `IDisposable` interface on the `Orm` class. The call is guaranteed to succeed. + +```csharp +var db = new Database(); +var orm = new Orm(db); +orm.Begin(); +orm.Write("some data"); +orm.Dispose(); +// => database has an internal state of State.Closed +``` diff --git a/exercises/concept/resource-cleanup/.docs/introduction.md b/exercises/concept/resource-cleanup/.docs/introduction.md new file mode 100644 index 0000000000..ffeafbf696 --- /dev/null +++ b/exercises/concept/resource-cleanup/.docs/introduction.md @@ -0,0 +1 @@ +If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset. diff --git a/exercises/concept/resource-cleanup/.meta/Example.cs b/exercises/concept/resource-cleanup/.meta/Example.cs new file mode 100644 index 0000000000..4e4fbd29f2 --- /dev/null +++ b/exercises/concept/resource-cleanup/.meta/Example.cs @@ -0,0 +1,55 @@ +using System; + +public class Orm : IDisposable +{ + private Database database; + + public Orm(Database database) + { + this.database = database; + } + + public void Begin() + { + try + { + database.BeginTransaction(); + } + catch (Exception e) + { + database.Dispose(); + } + } + + public void Write(string data) + { + try + { + database.Write(data); + } + catch (Exception e) + { + database.Dispose(); + } + } + + public void Commit() + { + try + { + database.EndTransaction(); + } + catch (Exception e) + { + database.Dispose(); + } + } + + public void Dispose() + { + if (database != null) + { + database.Dispose(); + } + } +} diff --git a/exercises/concept/resource-cleanup/.meta/config.json b/exercises/concept/resource-cleanup/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/resource-cleanup/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/resource-cleanup/.meta/design.md b/exercises/concept/resource-cleanup/.meta/design.md new file mode 100644 index 0000000000..50ca53dc36 --- /dev/null +++ b/exercises/concept/resource-cleanup/.meta/design.md @@ -0,0 +1,18 @@ +## Learning objectives + +- Know how to clean up resources using `IDisposable` in C# for managed resources. +- Know how and when to implement the `IDisposable` interface on your own classes. + +## Out of scope + +- resource lifetime - `using` dealt with in the `resource-lifetime` exercise +- dispose pattern: handled in a separate exercise + +## Concepts + +- `resource-cleanup` with `IDisposable` in C# and .NET. + +## Prerequisites + +- `exceptions` +- `interfaces`: `IDisposable` diff --git a/exercises/concept/resource-cleanup/ResourceCleanup.cs b/exercises/concept/resource-cleanup/ResourceCleanup.cs new file mode 100644 index 0000000000..a84acca014 --- /dev/null +++ b/exercises/concept/resource-cleanup/ResourceCleanup.cs @@ -0,0 +1,26 @@ +using System; + +public class Orm +{ + private Database database; + + public Orm(Database database) + { + this.database = database; + } + + public void Begin() + { + throw new NotImplementedException($"Please implement the Orm.Begin() method"); + } + + public void Write(string data) + { + throw new NotImplementedException($"Please implement the Orm.Write() method"); + } + + public void Commit() + { + throw new NotImplementedException($"Please implement the Orm.Commit() method"); + } +} diff --git a/exercises/concept/resource-cleanup/ResourceCleanup.csproj b/exercises/concept/resource-cleanup/ResourceCleanup.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/resource-cleanup/ResourceCleanup.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/resource-cleanup/ResourceCleanupTests.cs b/exercises/concept/resource-cleanup/ResourceCleanupTests.cs new file mode 100644 index 0000000000..59e20d100a --- /dev/null +++ b/exercises/concept/resource-cleanup/ResourceCleanupTests.cs @@ -0,0 +1,133 @@ +using System; +using System.Reflection; +using Xunit; +using example; + +public class ResourceCleanupTests +{ + [Fact] + public void Write_good() + { + var db = new Database(); + var orm = new Orm(db); + orm.Begin(); + orm.Write("good write"); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] { Database.State.DataWritten, "good write"}, actual); + } + + [Fact /*(Skip = "Remove this Skip property to run this test")*/] + public void Write_bad() + { + var db = new Database(); + var orm = new Orm(db); + orm.Begin(); + orm.Write("bad write"); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] { Database.State.Closed, "bad write"}, actual); + } + + [Fact /*(Skip = "Remove this Skip property to run this test")*/] + public void Commit_good() + { + var db = new Database(); + var orm = new Orm(db); + orm.Begin(); + orm.Write("good commit"); + orm.Commit(); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] { Database.State.Closed, "good commit"}, actual); + } + + [Fact /*(Skip = "Remove this Skip property to run this test")*/] + public void Commit_bad() + { + var db = new Database(); + var orm = new Orm(db); + orm.Begin(); + orm.Write("bad commit"); + orm.Commit(); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] { Database.State.Closed, "bad commit"}, actual); + } + + [Fact /*(Skip = "Remove this Skip property to run this test")*/] + public void Out_of_order() + { + var db = new Database(); + var orm = new Orm(db); + orm.Write("bad commit"); + orm.Commit(); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] { Database.State.Closed, string.Empty}, actual); + } + + [Fact /*(Skip = "Remove this Skip property to run this test")*/] + public void Disposable() + { + var db = new Database(); + var orm = new Orm(db); + orm.Begin(); + orm.Write("good data"); + var disposable = Assert.IsAssignableFrom(orm); + disposable.Dispose(); + object[] actual = {db.DbState, db.lastData}; + Assert.Equal(new object[] {Database.State.Closed, "good data"}, actual); + } +} + +// **** please do not modify the Database class **** +public class Database : IDisposable +{ + public enum State {TransactionStarted, DataWritten, Invalid, Closed} + + public State DbState { get; private set; } = State.Closed; + public string lastData = string.Empty; + + public void BeginTransaction() + { + if (DbState != State.Closed) + { + throw new InvalidOperationException(); + } + DbState = State.TransactionStarted; + } + + public void Write(string data) + { + if (DbState != State.TransactionStarted) + { + throw new InvalidOperationException(); + } + // this does something significant with the db transaction object + lastData = data; + if (data == "bad write") + { + DbState = State.Invalid; + throw new InvalidOperationException(); + } + + DbState = State.DataWritten; + } + + public void EndTransaction() + { + if (DbState != State.DataWritten && DbState != State.TransactionStarted) + { + throw new InvalidOperationException(); + } + // this does something significant to end the db transaction object + if (lastData == "bad commit") + { + DbState = State.Invalid; + throw new InvalidOperationException(); + } + + DbState = State.Closed; + } + + public void Dispose() + { + DbState = State.Closed; + } +} From 3dc0a37506026e06757054d30081430b93395552 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 3 Jul 2020 07:22:03 -0400 Subject: [PATCH 166/327] switch statements new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * switch-statements initial commit * switch-statements initial commit * switch-statements discussion draft before the PR * switch-statements * switch-statements rough proofing * Update languages/exercises/concept/switch-statements/.meta/Example.cs Co-authored-by: Erik Schierboom * switch-statements draft PR review * switch-statements prep for final PR * switch-statements prep for final PR * switch-statements prep for final PR * switch-statements proofing * Apply suggestions from code review Co-authored-by: Erik Schierboom * switch-statements late changes * switch-statements added track config.json * switch-statements detail omitted Co-authored-by: Erik Schierboom --- .../concept/switch-statements/.docs/after.md | 61 ++++++++++++ .../concept/switch-statements/.docs/hints.md | 25 +++++ .../switch-statements/.docs/instructions.md | 58 ++++++++++++ .../switch-statements/.docs/introduction.md | 41 +++++++++ .../switch-statements/.meta/Example.cs | 92 +++++++++++++++++++ .../switch-statements/.meta/config.json | 8 ++ .../concept/switch-statements/.meta/design.md | 20 ++++ .../switch-statements/SwitchStatements.cs | 36 ++++++++ .../switch-statements/SwitchStatements.csproj | 13 +++ .../SwitchStatementsTests.cs | 54 +++++++++++ 10 files changed, 408 insertions(+) create mode 100644 exercises/concept/switch-statements/.docs/after.md create mode 100644 exercises/concept/switch-statements/.docs/hints.md create mode 100644 exercises/concept/switch-statements/.docs/instructions.md create mode 100644 exercises/concept/switch-statements/.docs/introduction.md create mode 100644 exercises/concept/switch-statements/.meta/Example.cs create mode 100644 exercises/concept/switch-statements/.meta/config.json create mode 100644 exercises/concept/switch-statements/.meta/design.md create mode 100644 exercises/concept/switch-statements/SwitchStatements.cs create mode 100644 exercises/concept/switch-statements/SwitchStatements.csproj create mode 100644 exercises/concept/switch-statements/SwitchStatementsTests.cs diff --git a/exercises/concept/switch-statements/.docs/after.md b/exercises/concept/switch-statements/.docs/after.md new file mode 100644 index 0000000000..9e93b9d3a4 --- /dev/null +++ b/exercises/concept/switch-statements/.docs/after.md @@ -0,0 +1,61 @@ +Switch statements have a venerable [history][wiki-switch] in programming languages. They were introduced in [`C`][c-switch] where they were prized for their speed. That speed came at the cost of functionality which was very constrained. In C# the role of the switch statement has been expanded beyond integers. Switch statements can encompass any arbitrary type, value or reference. + +If you are coming from a functional language then working with switch statements (and [switch expressions][switch-expression] discussed elsewhere) is the nearest you will get in C# to using discriminated unions and pattern matching. However, they have nowhere near the discriminated union's power to enforce type safety. + +Simple switch statements resemble their `C` ancestors combining [`switch`][switch], [`case`][case], [`break`][switch-break] and [`default`][switch-default]. + +```csharp +int direction = GetDirection(); +switch (direction) +{ + case 1: + GoLeft(); + break; + case 2: + GoRight(); + break; + default: + MarkTime(); + break; +} +``` + +The above pattern can be used with any simple (primitives + strings) type. + +When reference types are added into the mix then [extra syntax][switch-pattern-matching] is involved, firstly to down cast the type and then to add guards ([`when`][switch-when]) although guards can be used with simple value cases. This is illustrated below: + +```csharp +Animal animal = GetAnimal(); + +switch(animal) +{ + case Dog dog: + dog.Bark(); + break; + case Cat cat when cat.Had8Lives(): + cat.IsCareful(); + cat.Meow(); + break; + case Cat cat: + cat.Meow(); + break; +} +``` + +- The `default` clause is optional but typically desirable. +- The `break` statement is mandatory for any non-empty `case` clause. +- Obviously the type of all the arguments to the `case` labels must be derived from the type of the `switch` argument. A `switch` argument of type `Object` obviously allows the widest range. +- The guard expression can include anything in scope not just members of the `case` argument. + +[switch statement][switch-statement] documentation provides an introduction to `switch` statements. + +[wiki-switch]: https://en.wikipedia.org/wiki/Switch_statement +[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[switch-expression]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#basic-example +[switch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-switch-section +[case]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#case-labels +[switch-break]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[switch-default]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case +[switch-pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern +[switch-when]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-case-statement-and-the-when-clause +[c-switch]: https://docs.microsoft.com/en-us/cpp/c-language/switch-statement-c?view=vs-2019 diff --git a/exercises/concept/switch-statements/.docs/hints.md b/exercises/concept/switch-statements/.docs/hints.md new file mode 100644 index 0000000000..a5703ec31d --- /dev/null +++ b/exercises/concept/switch-statements/.docs/hints.md @@ -0,0 +1,25 @@ +## General + +[switch statement][switch-statement] documentation provides an introduction to `switch` statements. + +### 1. Output descriptions of the players based on their shirt number + +- The [`break`][break] statement is useful. + +### 2. Raise an alert if an unknown shirt number is encountered. + +- The [`default`][default] statement is useful. + +### 3. Extend the coverage to include off field activity + +- [Pattern matching on types][switch-pattern-matching] is the key to this task. + +### 4. Where the manager has a name available we want that output instead of "the manager" + +- See this [documentation][switch-when] for the `when` keyword. + +[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[break]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[default]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case +[switch-pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern +[switch-when]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-case-statement-and-the-when-clause diff --git a/exercises/concept/switch-statements/.docs/instructions.md b/exercises/concept/switch-statements/.docs/instructions.md new file mode 100644 index 0000000000..8add616a36 --- /dev/null +++ b/exercises/concept/switch-statements/.docs/instructions.md @@ -0,0 +1,58 @@ +You are developing a system to help the staff of a football/soccer club's web site report on matches. Data is received from a variety of sources and piped into a single stream after being cleaned up. + +### 1. Output descriptions of the players based on their shirt number + +The team only ever plays a 4-3-3 formation and has never agreed with the 1965 change to the rules allowing for substitutions, never mind enlarged squads. + +The player descriptions are as follows: + +``` +1 -> "goalie" +2 -> "left back" +3 & 4 "center back" +5 -> "right back" +6, 7, & 8 -> "midfielder" +9 -> "left wing" +10 -> "striker" +11 -> "right wing" +``` + +Implement the static `PlayAnalyzer.OnField()` method to output a player description based on their shirt number. + +```csharp +PlayAnalyzer.AnalyzeOnField(10); +// => "striker" +``` + +### 2. Raise an alert if an unknown shirt number is encountered. + +Modify the `PlayAnalyzer.OffField()` method to throw an `ArgumentException` when a shirt number outside the range 1-11 is processed. + +### 3. Extend the coverage to include off field activity + +Implement the `PlayAnalyzer.OffField()` method to output description of activities and characters around the field of play. + +You receive a stream of data that has been cleaned. Your task is to analyse it and output appropriate text to help the journalists. + +The data comprises: + +- shirt numbers (any `int`) -> text as per on field analysis +- free form text (any `string`) -> the text unchanged +- incidents in play (`Incident` enum) -> "RedCard", "Foul" etc. +- opposing managers (objects of type `Manager`) -> "the manager" + +```csharp +PlayAnalyzer.AnalyzeOffField(Incident.RedCard); +// => "RedCard" +PlayAnalyzer.AnalyzeOffField((new Manager()); +// => "the manager" +``` + +### 4. Where the manager has a name available we want that output instead of "the manager" + +Modify the `PlayAnalyzer.OffField()` method to output any name such as "Jürgen Klopp" if there is one. If there is no name then the `Manager.Name` property is guaranteed to be an empty string rather than null. + +```csharp +PlayAnalyzer.AnalyzeOffField(new Manager("José Mário dos Santos Mourinho Félix", string.Empty)) +// => "José Mário dos Santos Mourinho Félix" +``` diff --git a/exercises/concept/switch-statements/.docs/introduction.md b/exercises/concept/switch-statements/.docs/introduction.md new file mode 100644 index 0000000000..3ebf3e64b1 --- /dev/null +++ b/exercises/concept/switch-statements/.docs/introduction.md @@ -0,0 +1,41 @@ +Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program". + +The mechanism involves the following keywords: `switch`, `case`, `break` and `default`. + +At their simplest they test a primitive or string expression and make a decision based on its value. For example: + +```csharp +string direction = GetDirection(); +switch (direction) +{ + case "left": + GoLeft(); + break; + case "right": + GoRight(); + break; + default: + MarkTime(); + break; +} +``` + +At their most sophisticated they introduce down casting `case :` and guards (`when`). + +```csharp +Animal animal = GetAnimal(); + +switch (animal) +{ + case Dog dog: + dog.Bark(); + break; + case Cat cat when cat.Had8Lives(): + cat.IsCareful(); + cat.Meow(); + break; + case Cat cat: + cat.Meow(); + break; +} +``` diff --git a/exercises/concept/switch-statements/.meta/Example.cs b/exercises/concept/switch-statements/.meta/Example.cs new file mode 100644 index 0000000000..ccf430b8f6 --- /dev/null +++ b/exercises/concept/switch-statements/.meta/Example.cs @@ -0,0 +1,92 @@ +using System; + +// **** please do not modify the Manager class **** +public class Manager +{ + public string Name { get; } + public string Activity { get; } + + public Manager(string name, string activity) + { + this.Name = name; + this.Activity = activity; + } +} + +// **** please do not modify the Incident enum **** +public enum Incident +{ + RedCard, + YellowCard, + Foul, + Injury +} + +public static class PlayAnalyzer +{ + public static string AnalyzeOnField(int shirtNum) + { + string playerDescription = string.Empty; + switch (shirtNum) + { + case 1: + playerDescription = "goalie"; + break; + case 2: + playerDescription = "left back"; + break; + case 5: + playerDescription = "right back"; + break; + case 3: + case 4: + playerDescription = "center back"; + break; + case 6: + case 7: + case 8: + playerDescription = "midfielder"; + break; + case 9: + playerDescription = "left wing"; + break; + case 11: + playerDescription = "right wing"; + break; + case 10: + playerDescription = "striker"; + break; + default: + throw new ArgumentException(); + } + + return playerDescription; + } + + public static string AnalyzeOffField(object report) + { + string description = string.Empty; + switch (report) + { + case int shirtNum: + description = AnalyzeOnField(shirtNum); + break; + case string freeFormText: + description = freeFormText; + break; + case Incident incident: + description = incident.ToString(); + break; + case Manager manager when !string.IsNullOrWhiteSpace(manager.Name): + description = manager.Name; + break; + case Manager manager: + description = "the manager"; + break; + default: + throw new ArgumentException(); + } + + return description; + } +} diff --git a/exercises/concept/switch-statements/.meta/config.json b/exercises/concept/switch-statements/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/switch-statements/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/switch-statements/.meta/design.md b/exercises/concept/switch-statements/.meta/design.md new file mode 100644 index 0000000000..e04542e114 --- /dev/null +++ b/exercises/concept/switch-statements/.meta/design.md @@ -0,0 +1,20 @@ +## Learning objectives + +- Know how to use simple `switch` statements. +- Know how to include pattern matching on types. +- Know how to include guards + +## Out of scope + +- switch expressions +- pattern matching tuples + +## Concepts + +- `switch-statements` + +## Prerequisites + +- `enums` +- `classes` +- `inheritance`: with type pattern matching the student needs to be aware of the need for a common base type including `Object`. diff --git a/exercises/concept/switch-statements/SwitchStatements.cs b/exercises/concept/switch-statements/SwitchStatements.cs new file mode 100644 index 0000000000..1c22962537 --- /dev/null +++ b/exercises/concept/switch-statements/SwitchStatements.cs @@ -0,0 +1,36 @@ +using System; + +public static class PlayAnalyzer +{ + public static string AnalyzeOnField(int shirtNum) + { + throw new NotImplementedException($"Please implement the (static) PlayAnalyzer.AnalyzeOnField() method"); + } + + public static string AnalyzeOffField(object report) + { + throw new NotImplementedException($"Please implement the (static) PlayAnalyzer.AnalyzeOffField() method"); + } +} + +// **** please do not modify the Manager class **** +public class Manager +{ + public string Name { get; } + public string Activity { get; } + + public Manager(string name, string activity) + { + this.Name = name; + this.Activity = activity; + } +} + +// **** please do not modify the Incident enum **** +public enum Incident +{ + RedCard, + YellowCard, + Foul, + Injury +} diff --git a/exercises/concept/switch-statements/SwitchStatements.csproj b/exercises/concept/switch-statements/SwitchStatements.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/switch-statements/SwitchStatements.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/switch-statements/SwitchStatementsTests.cs b/exercises/concept/switch-statements/SwitchStatementsTests.cs new file mode 100644 index 0000000000..34c5486823 --- /dev/null +++ b/exercises/concept/switch-statements/SwitchStatementsTests.cs @@ -0,0 +1,54 @@ +using System; +using Xunit; + +public class TuplesTest +{ + [Fact] + public void OnField_10() + { + Assert.Equal("striker", PlayAnalyzer.AnalyzeOnField(10)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OnField_bad() + { + Assert.Throws(() => PlayAnalyzer.AnalyzeOnField(1729)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_1() + { + Assert.Equal("goalie", PlayAnalyzer.AnalyzeOnField(1)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_text() + { + Assert.Equal("They think it's all over!", PlayAnalyzer.AnalyzeOffField("They think it's all over!")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_incident() + { + Assert.Equal("Foul", PlayAnalyzer.AnalyzeOffField(Incident.Foul)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_anonymous_manager() + { + Assert.Equal("the manager", PlayAnalyzer.AnalyzeOffField(new Manager(string.Empty, string.Empty))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_named_manager() + { + Assert.Equal("José Mário dos Santos Mourinho Félix", + PlayAnalyzer.AnalyzeOffField(new Manager("José Mário dos Santos Mourinho Félix", string.Empty))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void OffField_bad() + { + Assert.Throws(() => PlayAnalyzer.AnalyzeOffField(90.0f)); + } +} From d1adf47dfb02d71a7a32fad9d2ef9c97daa66a04 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 3 Jul 2020 07:54:28 -0400 Subject: [PATCH 167/327] concept exercises * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * exercise-concepts updated main doc for latest exercises added * exercise-concepts updated main doc for latest exercises added * [CI] Format code * concept-exercises added switch-statements to concept-exercises doc. * concept-exercises resolved merge conflict Co-authored-by: Erik Schierboom Co-authored-by: github-actions[bot] --- exercises/concept/object-initializers/.meta/design.md | 2 +- exercises/concept/resource-cleanup/.meta/design.md | 2 +- exercises/concept/switch-statements/.meta/design.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/concept/object-initializers/.meta/design.md b/exercises/concept/object-initializers/.meta/design.md index ea9642805e..ab869b6561 100644 --- a/exercises/concept/object-initializers/.meta/design.md +++ b/exercises/concept/object-initializers/.meta/design.md @@ -9,7 +9,7 @@ ## Concepts -- `object-initializers` +- `object-initializers`: Know how to initialize objects using object initialization syntax. Know how to initialize lists and dictionaries. Understand the relative advantages of constructors and initializers. ## Prerequisites diff --git a/exercises/concept/resource-cleanup/.meta/design.md b/exercises/concept/resource-cleanup/.meta/design.md index 50ca53dc36..9a552e0605 100644 --- a/exercises/concept/resource-cleanup/.meta/design.md +++ b/exercises/concept/resource-cleanup/.meta/design.md @@ -10,7 +10,7 @@ ## Concepts -- `resource-cleanup` with `IDisposable` in C# and .NET. +- `resource-cleanup`: Know how to clean up resources with `IDisposable` in C# and .NET. Understand the difference between managedd and unmanaged resources and the role of `IDisposable`. ## Prerequisites diff --git a/exercises/concept/switch-statements/.meta/design.md b/exercises/concept/switch-statements/.meta/design.md index e04542e114..e7f9f118ef 100644 --- a/exercises/concept/switch-statements/.meta/design.md +++ b/exercises/concept/switch-statements/.meta/design.md @@ -11,7 +11,7 @@ ## Concepts -- `switch-statements` +- `switch-statements`: Know how to use switch statements ## Prerequisites From d90692086f5309c3baa6e8f18a208093ebdec9b3 Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 8 Jul 2020 10:30:51 -0400 Subject: [PATCH 168/327] casting new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * regex up to date for changes made on PR #1727 * regex up to date for changes made on PR #1727 * casting recovering from repo problems * casting recovering from repo problems - code reflects agreed review points on PR #1851. Point on hierachy complexity is still open and not agreed. * casting dropped files that should not have been in this branch. * Apply suggestions from code review Co-authored-by: Erik Schierboom * casting review points * casting review points * casting review points * casting spelling * casting code and links * casting track config.json updated Co-authored-by: Erik Schierboom --- exercises/concept/casting/.docs/after.md | 155 ++++++++++++++++++ exercises/concept/casting/.docs/hints.md | 18 ++ .../concept/casting/.docs/instructions.md | 60 +++++++ .../concept/casting/.docs/introduction.md | 35 ++++ exercises/concept/casting/.meta/Example.cs | 44 +++++ exercises/concept/casting/.meta/config.json | 8 + exercises/concept/casting/.meta/design.md | 22 +++ exercises/concept/casting/Casting.cs | 33 ++++ exercises/concept/casting/Casting.csproj | 13 ++ exercises/concept/casting/CastingTests.cs | 54 ++++++ 10 files changed, 442 insertions(+) create mode 100644 exercises/concept/casting/.docs/after.md create mode 100644 exercises/concept/casting/.docs/hints.md create mode 100644 exercises/concept/casting/.docs/instructions.md create mode 100644 exercises/concept/casting/.docs/introduction.md create mode 100644 exercises/concept/casting/.meta/Example.cs create mode 100644 exercises/concept/casting/.meta/config.json create mode 100644 exercises/concept/casting/.meta/design.md create mode 100644 exercises/concept/casting/Casting.cs create mode 100644 exercises/concept/casting/Casting.csproj create mode 100644 exercises/concept/casting/CastingTests.cs diff --git a/exercises/concept/casting/.docs/after.md b/exercises/concept/casting/.docs/after.md new file mode 100644 index 0000000000..c4638fd885 --- /dev/null +++ b/exercises/concept/casting/.docs/after.md @@ -0,0 +1,155 @@ +Casting and type conversion [are different ways of changing an expression from one data type to another][wiki-casting]. + +The [C# documentation][type-testing-and-cast-operators] classifies type conversion as the use of the [`as` operator][as-operator] or [`is` operator][is-operator]. Casting is defined as the use of the [cast operator][cast-operator]. + +In C# very often, outside of the realm of numeric values and class hierarchies, you will have to make a conversion by calling some member of the "to" type such as [`Int32.Parse()`][int32-parse] which converts a string to an integer or by calling a member of the "from" type e.g. `object.ToString()`. Javascript and developers in other dynamic languages should be aware. + +Note that implicit an explicit cast [operators][operator-overloading] (discussed in (TODO cross-ref-tba)) are available which can bring fairly arbitrary casting to your own types. + +#### Casting Primitive Types - Implicit + +C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. Note in the documentation the exception for converting to real numbers where precision may be lost. + +An implicit cast is not signified by any special syntax. For example: + +```csharp +int myInt = 1729; +long myLong = myInt; +``` + +There is no implicit conversion of a numeric (or string) expression to `bool`. + +An expression of type `char` can be implicitly cast to `int`. The cast in the opposite direction must be explicit. Not all values of `int` are valid utf 16 chars. + +#### Casting Primitive Types - Explicit + +Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. + +Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown in the case of integers, or the "to" type variable may take a value of `Infinity` in the case of floats and doubles. + +An expression of type `int` can be explicitly cast to `char`. This may result in an invalid `char`. + +#### Casting Primitive Types - Examples + +```csharp +int largeInt = Int32.MaxValue; +int largeNegInt = Int32.MinValue; +ushort shortUnsignedInt = ushort.MaxValue; +float largeFloat = float.MaxValue; +float smallFloat = 17.29f; + +// implicit cast +int from_ushort = shortUnsignedInt; // 65535 +float from_int = largeInt; // -21474836E+09 +int from_char = 'a'; // 96 + +// explicit cast +uint from_largeInt = (uint)largeInt; // 2147483647 +uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) +int from_smallFloat = (int) smallFloat; // 17 +int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked) +char from_intc = (char) 32; // ' ' +char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown + +// no cast available +int fromString = Int32.Parse("42"); // 42 +string toString = largeInt.ToString(); // "2147483647" +int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown +``` + +See this [article][checked] for the _**checked**_ keyword. + +#### Type Conversion for types in a hierarchy + +Any type can be implicitly converted to its base class or interface. + +```csharp +IList ll = new List(); +``` + +A cast operator can be used to convert from a base to a derived class. + +```csharp +IList ll = new List(); +List l = (List)ll; +``` + +If the cast fails because the type of the expression being cast is not related to the type it is being cast to an instance of `InvalidCastException` is thrown. + +A more usual approach to these type conversions is to use the [`is`][is-operator] keyword: + +```csharp +interface IFoo { int Bar(); } +class Foo : IFoo { public int Bar() { return 42; }} +Object r = new Random(); +IFoo ifoo = new Foo(); +Object o = new Foo(); + +int result = 1729; + +if (ifoo is Foo foo) +{ + result = foo.Bar(); +} +// result == 42 + +result = 1729; +if (o is Foo foo2) +{ + result = foo2.Bar(); +} +// result == 42 + +result = 1729; +if (r is Foo foo3) +{ + result = foo3.Bar(); +} +// result == 1729 +``` + +The [`as`][as-operator] keyword fulfills a similar function to `is` e.g. `var foo = ifoo as Foo;`. In this example `foo` will be `null` if `ifoo` is not of type `Foo` otherwise `ifoo` will be assigned to it. + +#### Custom Cast Operator + +Types can define their own custom explicit and implicit [cast operators][custom-casts]. See (TODO cross-ref-tba) for coverage of this.. + +Examples of [explicit][big-integer-explicit] and [implicit][big-integer-implicit] casts in the BCL is conversions from the `BigInteger` struct to and from other numeric types + +#### Using `typeof` + +If you need to detect the precise type of an object then `is` may be a little too permissive as it will convert an object to a class or any of its base classes. `typeof` and `Object.GetType()` are the solution in this case. + +```csharp +object o = new List(); + +o is ICollection // true +o.GetType() == typeof(ICollection) // false +o is List // true +o.GetType() == typeof(List) // true +``` + +#### General + +- [Type testing and cast operators][type-testing-and-cast-operators]: introduction to type testing and casting. +- [cast operator][cast-operator]: the cast operator. +- [`is` operator][is-operator]: `is` operator reference. +- [`as`-operator][as-operator]: `as` operator reference. +- [`typeof` operator][typeof-operator]: `typeof` operator reference. +- [Type conversion exceptions][type-conversion-exceptions]: explains when a runtime exception is thrown when doing casts. + +[type-testing-and-cast-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast +[is-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator +[as-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator +[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression +[typeof-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator +[type-conversion-exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#type-conversion-exceptions-at-run-time +[wiki-casting]: https://en.wikipedia.org/wiki/Type_conversion +[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[explicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions +[int32-parse]: https://docs.microsoft.com/en-us/dotnet/api/system.int32.parse?view=netcore-3.1 +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[checked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked +[custom-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators +[big-integer-implicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_implicit?view=netcore-3.1 +[big-integer-explicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_explicit?view=netcore-3.1 diff --git a/exercises/concept/casting/.docs/hints.md b/exercises/concept/casting/.docs/hints.md new file mode 100644 index 0000000000..339d69c453 --- /dev/null +++ b/exercises/concept/casting/.docs/hints.md @@ -0,0 +1,18 @@ +## General + +- [Type testing and cast operators][type-testing-and-cast-operators]: introduction to type testing and casting. +- [cast operator][cast-operator]: the cast operator. + +## 1. Get display name for a member of the support team as long as they are staff members + +- Type conversions are discussed [here][is-operator]. + +## 3. Only designate principal security team members as priority personnel + +- Testing of type equality is covered in this [article][get-type] and in [this article][typeof-operator]. + +[type-testing-and-cast-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast +[is-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator +[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression +[typeof-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator +[get-type]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gettype?view=netcore-3.1#System_Object_GetType diff --git a/exercises/concept/casting/.docs/instructions.md b/exercises/concept/casting/.docs/instructions.md new file mode 100644 index 0000000000..350888d6a9 --- /dev/null +++ b/exercises/concept/casting/.docs/instructions.md @@ -0,0 +1,60 @@ +Our football club (first encountered in (TODO cross-ref-tba)) is soaring in the leagues, and you have been invited to do some more work, this time on the security pass printing system. + +The class hierarchy of the backroom staff is as follows + +``` +TeamSupport (interface) +├ Chairman +├ Manager +└ Staff (abstract) + ├ Physio + ├ OffensiveCoach + ├ GoalKeepingCoach + └ Security + ├ SecurityJunior + ├ SecurityIntern + └ PoliceLiaison +``` + +A complete implementation of the hierarchy is provided as part of the source code for the exercise. + +All data passed to the security pass maker has been validated and is guaranteed to be non-null. + +## 1. Get display name for a member of the support team as long as they are staff members + +Please implement the `SecurityPassMaker.GetDisplayName()` method. It should return the value of the `Title` field instances of all classes derived from `Staff` and, otherwise, "Too Important for a Security Pass". + +```csharp +var spm = new SecurityPassMaker(); +spm.GetDisplayName(new Manager()); +// => "Too Important for a Security Pass" +spm.GetDisplayName(new Physio()); +// => "The Physio" +``` + +## 2. Customize the display name for the security team + +Please modify the `SecurityPassMaker.GetDisplayName()` method. It should behave as in Task 1 except that if the staff member is a member of the security team (either of type `Security` or one of its derivatives) then the text " Priority Personnel" should be displayed after the title. + +```csharp +var spm = new SecurityPassMaker(); +spm.GetDisplayName(new Physio()); +// => "The Physio" +var spm2 = new SecurityPassMaker(); +spm2.GetDisplayName(new Security()); +// => "Security Team Member Priority Personnel" +spm2.GetDisplayName(new SecurityJunior()); +// => "Security Junior Priority Personnel" +``` + +## 3. Only designate principal security team members as priority personnel + +Please modify the `SecurityPassMaker.GetDisplayName()` method. It should behave as in Task 2 except that the text " Priority Personnel" should not be displayed for instances of type `SecurityJunior`, `SecurityIntern` and `PoliceLiaison`. + +```csharp +var spm2 = new SecurityPassMaker(); +spm2.GetDisplayName(new Security()); +// => "Security Team Member Priority Personnel" +spm2.GetDisplayName(new SecurityJunior()); +// => "Security Junior" +``` diff --git a/exercises/concept/casting/.docs/introduction.md b/exercises/concept/casting/.docs/introduction.md new file mode 100644 index 0000000000..d05ff9408e --- /dev/null +++ b/exercises/concept/casting/.docs/introduction.md @@ -0,0 +1,35 @@ +Casting and type conversion are different ways of changing an expression from one data type to another. + +An expression can be cast to another type with the cast operator `()`. + +```csharp +long l = 1000L; +int i = (int)l; + +object o = new Random(); +Random r = (Random)o; +``` + +If the types are not compatible an instance of `InvalidCastException` is thrown. In the case of numbers this indicates that the receiving type cannot represent the cast value. In the case of classes, one of the types must be derived from the other (this also applies trivially to structs). + +An alternative to _casting_ is _type conversion_ using the `is` operator. This is typically applied to reference and nullable types. + +```csharp +object o = new Random(); +if (o is Random rand) +{ + int ii = rand.Next(); + // now, do something random +} +``` + +If you need to detect the precise type of an object then `is` may be a little too permissive as it will return true for a class and any of the classes and interfaces from which it is derived directly or indirectly. `typeof` and `Object.GetType()` are the solution in this case. + +```csharp +object o = new List(); + +o is ICollection // true +o.GetType() == typeof(ICollection) // false +o is List // true +o.GetType() == typeof(List) // true +``` diff --git a/exercises/concept/casting/.meta/Example.cs b/exercises/concept/casting/.meta/Example.cs new file mode 100644 index 0000000000..1056e334d1 --- /dev/null +++ b/exercises/concept/casting/.meta/Example.cs @@ -0,0 +1,44 @@ +public class SecurityPassMaker +{ + public string GetDisplayName(TeamSupport support) + { + if (support is Staff staff) + { + string priorityPersonnelText = string.Empty; + if (staff.GetType() == typeof(Security)) + { + priorityPersonnelText = " Priority Personnel"; + } + + return staff.Title + priorityPersonnelText; + } + else + { + return "Too Important for a Security Pass"; + } + } +} + +/**** Please do not alter the code below ****/ + +public interface TeamSupport {string Title { get; } } + +public abstract class Staff : TeamSupport { public abstract string Title { get; }} + +public class Manager : TeamSupport { public string Title { get; } = "The Manager"; } + +public class Chairman : TeamSupport { public string Title { get; } = "The Manager"; } + +public class Physio : Staff { public override string Title { get; } = "The Physio"; } + +public class OffensiveCoach : Staff { public override string Title { get; } = "Offensive Coach"; } + +public class GoalKeepingCoach : Staff { public override string Title { get; } = "Goal Keeping Coach"; } + +public class Security : Staff { public override string Title { get; } = "Security Team Member"; } + +public class SecurityJunior : Security { public override string Title { get; } = "Security Junior"; } + +public class SecurityIntern : Security { public override string Title { get; } = "Security Intern"; } + +public class PoliceLiaison : Security { public override string Title { get; } = "Police Liaison Officer"; } diff --git a/exercises/concept/casting/.meta/config.json b/exercises/concept/casting/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/casting/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/casting/.meta/design.md b/exercises/concept/casting/.meta/design.md new file mode 100644 index 0000000000..89770a2ecd --- /dev/null +++ b/exercises/concept/casting/.meta/design.md @@ -0,0 +1,22 @@ +## Learning objectives + +- Know what explicit and implicit casts are. +- Know how to do an explicit cast. +- Know how to use `is` and `as` to cast types. +- Know how to use the `typeof` operator. +- Pattern matching on types. + +## Out of scope + +- Custom explicit and implicit cast operators. +- Memory and performance characteristics. + +## Concepts + +- `casting`: know what explicit and implicit casts are; know how to do an explicit cast; know how to use `is` and `as` to convert between types. + +## Prerequisites + +- `numbers`: know how to cast numbers and what explicit and implicit numeric casts are. +- `inheritance`: work with inheritance to show when casting can be reasonably used. +- `exceptions`: know about exceptions to understand what happens when an explicit cast fails. diff --git a/exercises/concept/casting/Casting.cs b/exercises/concept/casting/Casting.cs new file mode 100644 index 0000000000..6810d504cc --- /dev/null +++ b/exercises/concept/casting/Casting.cs @@ -0,0 +1,33 @@ +using System; + +public class SecurityPassMaker +{ + public string GetDisplayName(TeamSupport support) + { + throw new NotImplementedException($"Please implement the SecurityPassMaker.GetDisplayName() method"); + } +} + +/**** Please do not alter the code below ****/ + +public interface TeamSupport {string Title { get; } } + +public abstract class Staff : TeamSupport { public abstract string Title { get; }} + +public class Manager : TeamSupport { public string Title { get; } = "The Manager"; } + +public class Chairman : TeamSupport { public string Title { get; } = "The Manager"; } + +public class Physio : Staff { public override string Title { get; } = "The Physio"; } + +public class OffensiveCoach : Staff { public override string Title { get; } = "Offensive Coach"; } + +public class GoalKeepingCoach : Staff { public override string Title { get; } = "Goal Keeping Coach"; } + +public class Security : Staff { public override string Title { get; } = "Security Team Member"; } + +public class SecurityJunior : Security { public override string Title { get; } = "Security Junior"; } + +public class SecurityIntern : Security { public override string Title { get; } = "Security Intern"; } + +public class PoliceLiaison : Security { public override string Title { get; } = "Police Liaison Officer"; } diff --git a/exercises/concept/casting/Casting.csproj b/exercises/concept/casting/Casting.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/casting/Casting.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/casting/CastingTests.cs b/exercises/concept/casting/CastingTests.cs new file mode 100644 index 0000000000..e9be8cd8e3 --- /dev/null +++ b/exercises/concept/casting/CastingTests.cs @@ -0,0 +1,54 @@ +using System; +using Xunit; + +public class CastingTests +{ + [Fact] + public void DisplaySecurityPass_manager() + { + var spm = new SecurityPassMaker(); + Assert.Equal("Too Important for a Security Pass", spm.GetDisplayName(new Manager())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_pysio() + { + var spm = new SecurityPassMaker(); + Assert.Equal("The Physio", spm.GetDisplayName(new Physio())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_pysio_with_alert() + { + var spm = new SecurityPassMaker(); + Assert.Equal("The Physio", spm.GetDisplayName(new Physio())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_security() + { + var spm = new SecurityPassMaker(); + Assert.Equal("Security Team Member Priority Personnel", spm.GetDisplayName(new Security())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_security_junior() + { + var spm = new SecurityPassMaker(); + Assert.Equal("Security Junior", spm.GetDisplayName(new SecurityJunior())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_security_police_liaison() + { + var spm = new SecurityPassMaker(); + Assert.Equal("Police Liaison Officer", spm.GetDisplayName(new PoliceLiaison())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySecurityPass_security_intern() + { + var spm = new SecurityPassMaker(); + Assert.Equal("Security Intern", spm.GetDisplayName(new SecurityIntern())); + } +} From 355f912935c2b0981f2670a98d8b3cb6945c8fba Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 8 Jul 2020 23:40:16 -0400 Subject: [PATCH 169/327] structs new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * structs - addresses review points from #1812 * structs proofing * structs config.json Co-authored-by: Erik Schierboom --- exercises/concept/structs/.docs/after.md | 93 +++++++++++++++++++ exercises/concept/structs/.docs/hints.md | 22 +++++ .../concept/structs/.docs/instructions.md | 47 ++++++++++ .../concept/structs/.docs/introduction.md | 28 ++++++ exercises/concept/structs/.meta/Example.cs | 76 +++++++++++++++ exercises/concept/structs/.meta/config.json | 8 ++ exercises/concept/structs/.meta/design.md | 30 ++++++ exercises/concept/structs/Structs.cs | 42 +++++++++ exercises/concept/structs/Structs.csproj | 13 +++ exercises/concept/structs/StructsTests.cs | 54 +++++++++++ 10 files changed, 413 insertions(+) create mode 100644 exercises/concept/structs/.docs/after.md create mode 100644 exercises/concept/structs/.docs/hints.md create mode 100644 exercises/concept/structs/.docs/instructions.md create mode 100644 exercises/concept/structs/.docs/introduction.md create mode 100644 exercises/concept/structs/.meta/Example.cs create mode 100644 exercises/concept/structs/.meta/config.json create mode 100644 exercises/concept/structs/.meta/design.md create mode 100644 exercises/concept/structs/Structs.cs create mode 100644 exercises/concept/structs/Structs.csproj create mode 100644 exercises/concept/structs/StructsTests.cs diff --git a/exercises/concept/structs/.docs/after.md b/exercises/concept/structs/.docs/after.md new file mode 100644 index 0000000000..05e95c3a4e --- /dev/null +++ b/exercises/concept/structs/.docs/after.md @@ -0,0 +1,93 @@ +C# `struct`s are closely related `class`s. They have state and behavior. They can have the same kinds of members: constructors, methods, fields, properties, etc. + +Fields and properties can be simple types, `struct`s or reference types. `struct`s observe the same rules about scope, read/write rules and access levels as do `class`s. + +```csharp +enum Unit +{ + Kg, + Lb +} + +struct Weight +{ + private double count; + private Unit unit; + + public Weight(double count, Unit unit) + { + this.count = count; + this.unit = unit; + } + + public override string ToString() + { + return count.ToString() + unit.ToString(); + } +} + +new Weight(77.5, Unit.Kg).ToString(); +// => "77.6Kg" +``` + +One of the main things to remember is that when one struct is assigned to a variable or passed as a parameter the values are copied across so changes to the original variable will not affect the copied one and vice versa. In summary, `struct`s are **value types**. + +This [article][class-or-struct] discusses the differences between `struct`s and `class`s. You will see from the article that `struct`s tend to be lightweight and [immutable][structs-immutable] although this guidance is not enforced (by default) by the compiler or runtime. + +There are a couple of things that you will come up against (and about which the compiler will remind you): + +1. Members of a `struct` cannot be initialized inline. +2. A `struct` cannot be inherited +3. A `struct` always has a default constructor even if a non-default one is provided, and you cannot provide an explicit parameterless constructor. + +As a result of points 1 and 3 above there is no way for the developer of a `struct` to prevent invalid instances from coming into existence. + +#### Common structs + +You will see from the documentation that there is a close relationship between primitives and structs. See [`Int32/int]`][int32], for an example. A more conventional example of a`struct`is the type [`TimeSpan`][time-span]. + +Instances of `TimeSpan` behave much like numbers with comparison operators like `>` and `<` and arithmetic operators. You can implement these operators for your own `struct`s when you need them. + +One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable`. Although `struct`s cannot be derived from other `struct`s they can implement interfaces. + +#### Equality + +Equality testing for `struct`s can often be much simpler than that for `class`s as it simply compares fields for equality by default. There is no need to override `object.Equals()` (or `GetHashCode()`). Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use. Effectively, this means that structs used in this way should be immutable. See (TODO cross-ref-tba). + +In contrast to the method, `Equals()`, there is no default implementation of the equality operators, `==` and `!=`. If your `struct` needs them then you will have to implement them. + +On the other hand, this [article][equality] describes how performance can be optimised by creating your own custom `Equals()` and `GetHashCode()` method as is often done with `class`s. The difference in the case of this exercise was about 20% in a not very rigorous comparison but that may be on the low side because all the fields are of the same type - see below. + +There are discussions on the [web][equality-performance] about speed improvements, where the `Equals()` method is not overridden, if all fields are of the same type. The difference in this exercise of including disparate fields was about 60%. This is not mentioned in Microsoft's documentation so that makes it an un-documented implementation detail, and it should be exploited judiciously. + +```csharp +public bool Equals(Weight other) +{ + return count.Equals(other.count) && unit.Equals(other.unit); +} + +public override bool Equals(object obj) +{ + return obj is Weight other && Equals(other); +} + +public override int GetHashCode() +{ + return HashCode.Combine(count, unit); +} +``` + +#### General + +- [structs][structs]: introduction to structs. +- [class-or-struct][class-or-struct]: lists the guidelines for choosing between a struct and class. + +[structs-immutable]: https://stackoverflow.com/a/3753640/96167 +[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type +[equality-performance]: https://medium.com/@semuserable/c-journey-into-struct-equality-comparison-deep-dive-9693f74562f1 +[structs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct +[class-or-struct]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct +[int32]: https://docs.microsoft.com/en-us/dotnet/api/system.int32?view=netcore-3.1 +[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-3.1 diff --git a/exercises/concept/structs/.docs/hints.md b/exercises/concept/structs/.docs/hints.md new file mode 100644 index 0000000000..250e8458e8 --- /dev/null +++ b/exercises/concept/structs/.docs/hints.md @@ -0,0 +1,22 @@ +## General + +- [structs][structs]: introduction to structs. + +## 1. Define a Plot + +- This [article][struct-instantiation] discusses instantiating a `struct`. + +## 2. Speculators can stake their claim by specifying a plot identified by its dimensions + +- Hash codes are discussed [here][get-hash-code]. +- Sets are discussed [here][sets]. + +## 3. Check whether the current claim is the same as the last one. + +- Object equality is discussed in this [article][equals] + +[structs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct +[struct-instantiation]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct#instantiation-of-a-structure-type +[get-hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1#System_Object_GetHashCode +[sets]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ diff --git a/exercises/concept/structs/.docs/instructions.md b/exercises/concept/structs/.docs/instructions.md new file mode 100644 index 0000000000..cd1152a9e2 --- /dev/null +++ b/exercises/concept/structs/.docs/instructions.md @@ -0,0 +1,47 @@ +You have been tasked by the claims department of Isaacs Asteroid Exploration Co. to improve the performance of their land claim system. + +Every time a new asteroid is ready for exploitation speculators are invited to stake their claim to a plot of land. The asteroid's land is divided into 4 sided plots. Speculators claim the land by specifying its dimensions. + +Your goal is to develop a performant system to handle the land rush that has in the past caused the website to crash. + +The unit of measure is 100 meters but can be ignored in these tasks. + +## 1. Define a Plot + +Complete the implementation of the `Plot` struct which comprises 4 coord structs (which it accepts in its constructor). + +## 2. Speculators can stake their claim by specifying a plot identified by its dimensions + +Implement the `ClaimsHandler.StakeClaim()` method to allow a claim to be registered. + +Implement the `ClaimsHandler.IsClaimStaked()` method to determine whether a claim has been staked. + +```csharp +var ch = new ClaimsHandler(); +ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); +ch.IsClaimStaked(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); +// => true +``` + +## 3. Check whether the current claim is the same as the last one. + +Implement the `ClaimsHandler.IsLastClaim()` method to compare the current claim with the previous one. + +```csharp +var ch = new ClaimsHandler(); +ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); +ch.IsLastClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); +// => true +``` + +## 4. Find the plot claimed that has the longest side for research purposes + +Implement the `ClaimsHandler.GetClaimWithLongestSide()` method to examine all registered claims and return the plot with the longest side. + +```csharp +var ch = new ClaimsHandler(); +ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); +ch.StakeClaim(new Plot(new Coord(1,1), new Coord(20,1), new Coord(1,2), new Coord(2,2))); +ch.GetClaimWithLongestSide(); +// => new Plot(new Coord(1,1), new Coord(20,1), new Coord(1,2), new Coord(2,2)) +``` diff --git a/exercises/concept/structs/.docs/introduction.md b/exercises/concept/structs/.docs/introduction.md new file mode 100644 index 0000000000..6b1142d00f --- /dev/null +++ b/exercises/concept/structs/.docs/introduction.md @@ -0,0 +1,28 @@ +C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections. + +```csharp +enum Unit +{ + Kg, + Lb +} +struct Weight +{ + private double count; + private Unit unit; + + public Weight(double count, Unit unit) + { + this.count = count; + this.unit = unit; + } + + public override string ToString() + { + return count.ToString() + unit.ToString(); + } +} + +new Weight(77.5, Unit.Kg).ToString(); +// => "77.6Kg" +``` diff --git a/exercises/concept/structs/.meta/Example.cs b/exercises/concept/structs/.meta/Example.cs new file mode 100644 index 0000000000..64afd3b8f1 --- /dev/null +++ b/exercises/concept/structs/.meta/Example.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +public struct Coord +{ + public Coord(ushort x, ushort y) + { + X = x; + Y = y; + } + + public ushort X { get; } + public ushort Y { get; } +} + +public struct Plot +{ + public Plot(Coord topLeft, Coord topRight, Coord bottomLeft, Coord bottomRight) + { + TopLeft = topLeft; + TopRight = topRight; + BottomLeft = bottomLeft; + BottomRight = bottomRight; + } + + public Coord TopLeft { get; } + public Coord TopRight { get; } + public Coord BottomLeft { get; } + public Coord BottomRight { get; } + + public ushort GetLongestSide() + { + return (ushort)Math.Max( + TopRight.X - TopLeft.X, + Math.Max(BottomRight.X - BottomLeft.X, + Math.Max(BottomRight.Y - TopRight.Y + ,BottomLeft.Y - TopLeft.Y))); + } +} + +public class ClaimsHandler +{ + private ISet plots = new HashSet(); + private Plot lastClaim; + + public void StakeClaim(Plot plot) + { + lastClaim = plot; + plots.Add(plot); + } + + public bool IsClaimStaked(Plot plot) + { + return plots.Contains(plot); + } + + public bool IsLastClaim(Plot plot) + { + return lastClaim.Equals(plot); + } + + public Plot GetClaimWithLongestSide() + { + Plot longest = new Plot(); + foreach (Plot plot in plots) + { + if (plot.GetLongestSide() > longest.GetLongestSide()) + { + longest = plot; + } + } + + return longest; + } +} diff --git a/exercises/concept/structs/.meta/config.json b/exercises/concept/structs/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/structs/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/structs/.meta/design.md b/exercises/concept/structs/.meta/design.md new file mode 100644 index 0000000000..436b788e6d --- /dev/null +++ b/exercises/concept/structs/.meta/design.md @@ -0,0 +1,30 @@ +## Learning objectives + +- Know what structs are. +- Know how to define a `struct`. +- Know how to add members to structs. +- Know the differences between structs and classes. + +## Out of scope + +- ref structs. +- ref returns +- ref locals +- readonly structs +- Struct finalizers. +- `Span`/`Memory` +- `stackalloc` + +## Concepts + +This Concepts Exercise's Concepts are: + +- `structs`: know what structs are; know how to define a `struct`; know how to add members to structs; know the differences between structs and classes. + +## Prequisites + +- `inheritance`: know that all types are derived from `object`. +- `classes`: know how to define and work with classes. +- `numbers`: +- `sets`: know how to define and work with a `HashSet` +- `signed-integers`/`integral-numbers`: for `ushort` diff --git a/exercises/concept/structs/Structs.cs b/exercises/concept/structs/Structs.cs new file mode 100644 index 0000000000..955388be50 --- /dev/null +++ b/exercises/concept/structs/Structs.cs @@ -0,0 +1,42 @@ +using System; + +public struct Coord +{ + public Coord(ushort x, ushort y) + { + X = x; + Y = y; + } + + public ushort X { get; } + public ushort Y { get; } +} + +public struct Plot +{ + // TODO: Complete implementation of the Plot struct +} + + +public class ClaimsHandler +{ + public void StakeClaim(Plot plot) + { + throw new NotImplementedException("Please implement the ClaimsHandler.StakeClaim() method"); + } + + public bool IsClaimStaked(Plot plot) + { + throw new NotImplementedException("Please implement the ClaimsHandler.IsClaimStaked() method"); + } + + public bool IsLastClaim(Plot plot) + { + throw new NotImplementedException("Please implement the ClaimsHandler.IsLastClaim() method"); + } + + public Plot GetClaimWithLongestSide() + { + throw new NotImplementedException("Please implement the ClaimsHandler.GetClaimWithLongestSide() method"); + } +} diff --git a/exercises/concept/structs/Structs.csproj b/exercises/concept/structs/Structs.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/structs/Structs.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/structs/StructsTests.cs b/exercises/concept/structs/StructsTests.cs new file mode 100644 index 0000000000..94d2067c53 --- /dev/null +++ b/exercises/concept/structs/StructsTests.cs @@ -0,0 +1,54 @@ +using System; +using Xunit; + +public class StructsTests +{ + [Fact] + public void IsClaimed_yes() + { + var ch = new ClaimsHandler(); + ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + var claimed = ch.IsClaimStaked(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + Assert.True(claimed); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsClaimed_no() + { + var ch = new ClaimsHandler(); + ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + var claimed = ch.IsClaimStaked(new Plot(new Coord(1,0), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + Assert.False(claimed); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsLastClaim_yes() + { + var ch = new ClaimsHandler(); + ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + ch.StakeClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + var lastClaim = ch.IsLastClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + Assert.True(lastClaim); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsLastClaim_no() + { + var ch = new ClaimsHandler(); + ch.StakeClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + var lastClaim = ch.IsLastClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + Assert.False(lastClaim); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void GetLongestSide() + { + var ch = new ClaimsHandler(); + var longer = new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2)); + var shorter = new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2)); + ch.StakeClaim(longer); + ch.StakeClaim(shorter); + Assert.Equal(longer, ch.GetClaimWithLongestSide()); + } +} From cd9a05b1163c0c71a1a2952c9f4622b925dbf413 Mon Sep 17 00:00:00 2001 From: Mike May Date: Sat, 11 Jul 2020 09:38:22 -0400 Subject: [PATCH 170/327] regular expressions new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * regex up to date for changes made on PR #1727 * regex up to date for changes made on PR #1727 * regex dropped files that should not have been in this branch. * regex after.md * regex hints and intro * regex proofing * regex proofing * regex proofing * regex updated track config.json * regex updated track config.json * Apply suggestions from code review Co-authored-by: Erik Schierboom Co-authored-by: Erik Schierboom --- .../regular-expressions/.docs/after.md | 66 ++++++++++++ .../regular-expressions/.docs/hints.md | 33 ++++++ .../regular-expressions/.docs/instructions.md | 100 ++++++++++++++++++ .../regular-expressions/.docs/introduction.md | 1 + .../regular-expressions/.meta/Example.cs | 56 ++++++++++ .../regular-expressions/.meta/config.json | 8 ++ .../regular-expressions/.meta/design.md | 23 ++++ .../regular-expressions/RegularExpressions.cs | 30 ++++++ .../RegularExpressions.csproj | 13 +++ .../RegularExpressionsTests.cs | 77 ++++++++++++++ 10 files changed, 407 insertions(+) create mode 100644 exercises/concept/regular-expressions/.docs/after.md create mode 100644 exercises/concept/regular-expressions/.docs/hints.md create mode 100644 exercises/concept/regular-expressions/.docs/instructions.md create mode 100644 exercises/concept/regular-expressions/.docs/introduction.md create mode 100644 exercises/concept/regular-expressions/.meta/Example.cs create mode 100644 exercises/concept/regular-expressions/.meta/config.json create mode 100644 exercises/concept/regular-expressions/.meta/design.md create mode 100644 exercises/concept/regular-expressions/RegularExpressions.cs create mode 100644 exercises/concept/regular-expressions/RegularExpressions.csproj create mode 100644 exercises/concept/regular-expressions/RegularExpressionsTests.cs diff --git a/exercises/concept/regular-expressions/.docs/after.md b/exercises/concept/regular-expressions/.docs/after.md new file mode 100644 index 0000000000..74e879a251 --- /dev/null +++ b/exercises/concept/regular-expressions/.docs/after.md @@ -0,0 +1,66 @@ +The .NET base class libraries provide the [`Regex`][regex] class for processing of regular expressions. + +See this [article][regex-comparison] for a comparison of C# with other flavours of regular expressions. + +#### Capture Groups + +One aspect to consider is that of capture groups which return parts of the text matching various parts of the regex pattern. The approach to capture groups needs getting used to. See this [documentation][capture]. + +Note that there is a hierarchy where capture groups, `(?pattern)`, are involved: + +- where a set of zero or more matches is returned (one for each match found in the text). +- Each match contains a number of capture groups +- Each group contains a number of captures. + +In addition: + +- `Match` is derived from `Group` +- `Group` is derived from `Capture` + +Caveats: + +- The safest approach is to use named captures. +- Capture groups do generally occur in the `Groups` collection in the same order as they appear in the text. +- `Groups[0]` appears to relate to the entire match. +- `Groups[].Value` is almost certainly what you are interested in. Individual captures (other than `Caputures[0]`) appear to be for intended for diagnostic purposes if they are present. + +#### Regex Options + +Familiarise yourself with [`RegexOptions`][regex-options]. + +As well as the usual `IgnoreCase` options there are ones for `MultiLine` which is useful for processing multiple lines of text in one go and `IgnorePatternWhitespace` which when coupled with verbatim strings, string interpolation and comments can be very expressive as shown in this illustration: + +```csharp +const string PREAMBLE = "preamble"; +const string PWTEXT = "pwtext"; +const string PW = "pw"; +const string SPACE = "space"; +const string POSTAMBLE = "postamble"; + +var pattern = $@" + ^ + (?<{PREAMBLE}>.*) # any text + (?<{PWTEXT}>password) # the literal text - password + (?<{SPACE}>\s+) + (?<{PW}>\w*) # the password itself + (?<{POSTAMBLE}>.*) # any text + $ + "; + +var rewrittenLine = $"{grps[PREAMBLE].Value}{grps[PWTEXT].Value}{grps[SPACE].Value}{mask}{grps[POSTAMBLE].Value}"; +``` + +Another option of interest is `RegexOptions.Compiled` for [compiled][regex-compilation] regexes. + +#### General + +- [regular expressions][regular-expressions] documentation describes regexes and the flavour built into the .NET libraries. +- [Regex][regex] documentation describing the built-in library class. + +[regular-expressions]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference +[regex]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1 +[so-groups-and-captures]: https://stackoverflow.com/questions/3320823/whats-the-difference-between-groups-and-captures-in-net-regular-expression +[regex-comparison]: https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines +[capture]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.capturecollection?view=netcore-3.1 +[regex-options]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions?view=netcore-3.1 +[regex-compilation]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices diff --git a/exercises/concept/regular-expressions/.docs/hints.md b/exercises/concept/regular-expressions/.docs/hints.md new file mode 100644 index 0000000000..8774ee169d --- /dev/null +++ b/exercises/concept/regular-expressions/.docs/hints.md @@ -0,0 +1,33 @@ +## General + +- [regular expressions][regular-expressions] documentation describes regexes and the flavour built into the .NET libraries. +- [Regex][regex] documentation describing the built-in library class. + +### 1. Identify garbled log lines + +- See [this discussion][ismatch] of matching. + +### 2. Split the log line + +- [This][split] article shows an approach to splitting lines. + +### 3. Count the number of lines containing a password + +- See [this discussion][multiple-matches] of multiple matches and [this][multi-line] on multi-line searches. + +### 4. Remove artifacts from log + +- [This article][replace] shows how text can be replaced. + +### 5. List lines with extremely weak passwords so the guilty can be punished + +- Capture groups are discussed [here][capture-groups]. + +[regular-expressions]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference +[regex]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1 +[ismatch]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.ismatch?view=netcore-3.1 +[split]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.split?view=netcore-3.1 +[multiple-matches]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.matches?view=netcore-3.1 +[multi-line]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions?view=netcore-3.1 +[replace]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex.replace?view=netcore-3.1 +[capture-groups]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/grouping-constructs-in-regular-expressions diff --git a/exercises/concept/regular-expressions/.docs/instructions.md b/exercises/concept/regular-expressions/.docs/instructions.md new file mode 100644 index 0000000000..fa280fa9fb --- /dev/null +++ b/exercises/concept/regular-expressions/.docs/instructions.md @@ -0,0 +1,100 @@ +This exercise addresses the parsing of log files. + +After a recent security review you have been asked to clean up the organisation's archived log files. + +All strings passed to the methods are guaranteed to be non-null and leading and without trailing spaces. + +### 1. Identify garbled log lines + +You need some idea of how many log lines in your archive do not comply with current standards. You believe that a simple test reveals whether a log line is valid. To be considered valid a line should begin with one of the following strings: + +- [TRC] +- [DBG] +- [INF] +- [WRN] +- [ERR] +- [FTL] + +Implement the `LogParser.IsValidLine()` method to return `false` if a string is not valid otherwise `true`. + +```csharp +var lp = new LogParser(); +lp.IsMatch("[ERR] A good error here"); +// => true +lp.IsMatch("Any old [ERR] text"); +// => false +lp.IsMatch("[BOB] Any old text"); +// => false +``` + +### 2. Split the log line + +A new team has joined the organization, and you find their log files are using a strange separator for "fields". Instead of something sensible like a colon ":" they use a string such as "<--->" or "<=>" (because it's prettier) in fact any string that has a first character of "<" and a last character of ">" and any combination of the following characters "^", "\*", "=" and "-" in between. + +Implement the `LogParser.SplitLogLine()` method that takes a line and returns an array of strings each of which contains a field. + +```csharp +var lp = new LogParser(); +lp.SplitLogLine("Section 1<===>Section 2<^-^>Section 3"); +// => {"Section 1", "Section 2", "Section 3"} +``` + +### 3. Count the number of lines containing a password + +A log line is considered to contain a password if it contains the literal string "password" followed by a space and then a word (the actual password). + +It is important to find any passwords included in a file. These will be dealt with automatically, but the team needs to know how about passwords occurred in quoted text so that they can be examined manually. + +Implement the `LogParser.CountQuotedPasswords()`method to provide an indication of the likely scale of the manual exercise. + +The literal string "password" may be in upper or lower case or any combination. + +Lines passed to the routine may or may not be valid as defined in task 1. We process them in the same way, whether or not they are valid. + +```csharp +string lines = + "[INF] passWord " + Environment.NewLine + + "\"passWord\"" + Environment.NewLine + + "[INF] \"The secret password was added by the user\""; + +var lp = new LogParser(); +lp.CountQuotedPasswords(lines); +// => 2 +``` + +### 4. Remove artifacts from log + +You have found that some upstream processing of the logs has been scattering the text "end-of-line" followed by a line number (without an intervening space) throughout the logs. + +Implement the `LogParser.RemoveEndOfLineText()` method to take a string and remove the end-of-line text and return a "clean" string. + +Lines not containing end-of-line text should be returned unmodified. + +Just remove the end of line string. Do not attempt to adjust the whitespaces. + +```csharp +var lp = new LogParser(); +lp.RemoveEndOfLineText("[INF] end-of-lline23033 Network Falure end-of-line27"); +// => "[INF] Network Failure " +``` + +### 5. List lines with extremely weak passwords so the guilty can be punished + +Before expunging the passwords from the file we need to list any instances where passwords begin with the text "password". + +Implement the `LogParser.ListLinesWithPasswords()` method to print out the offending password followed by the complete line. + +Lines with quoted passwords have already been removed and you process lines irrespective of whether they are valid (as per task 1). + +Lines containing an offending password should be returned prefixed with ": ". + +Lines not containing an offending password should be returned prefixed with "-------: ". + +```csharp +var lp = new LogParser(); +lp.ListLinesWithPasswords(new string[] {"my passwordsecret is great"}); +// => "passwordsecre: my passwordsecret is great" +lp.ListLinesWithPasswords(new string[] {"my password secret"}); +// => {"--------: my password secret"} + +``` diff --git a/exercises/concept/regular-expressions/.docs/introduction.md b/exercises/concept/regular-expressions/.docs/introduction.md new file mode 100644 index 0000000000..1256179199 --- /dev/null +++ b/exercises/concept/regular-expressions/.docs/introduction.md @@ -0,0 +1 @@ +The .NET base class libraries provide the `Regex` class for processing of regular expressions. diff --git a/exercises/concept/regular-expressions/.meta/Example.cs b/exercises/concept/regular-expressions/.meta/Example.cs new file mode 100644 index 0000000000..2b88d78c34 --- /dev/null +++ b/exercises/concept/regular-expressions/.meta/Example.cs @@ -0,0 +1,56 @@ +using System.Text.RegularExpressions; + +public class LogParser +{ + public bool IsMatch(string text) + { + const string searchArg = @"^(\[TRC\] | \[DBG\] | \[INF\] | \[ERR\] | \[WRN\] | \[FTL\])"; + return Regex.IsMatch(text, searchArg, RegexOptions.IgnorePatternWhitespace); + } + + public string[] SplitLogLine(string text) + { + return Regex.Split(text, "<[*^=-]*>"); + } + + public int CountQuotedPasswords(string lines) + { + bool[] results = new bool[lines.Length]; + var regex = new Regex(@"^.*""[^\\""]*password[^\\""]*"".*$", + RegexOptions.IgnoreCase | RegexOptions.Multiline); + var matches = regex.Matches(lines); + return matches.Count; + } + + public string RemoveEndOfLineText(string line) + { + string pattern = @"end-of-Line\d+"; + + return Regex.Replace(line, pattern, string.Empty, + RegexOptions.IgnoreCase); + } + + public string[] ListLinesWithPasswords(string[] lines) + { + var pattern = @".*\s(?password\S+).*"; + + string[] outlines = new string[lines.Length]; + var regex = new Regex(pattern, RegexOptions.IgnoreCase); + for (int i = 0; i < lines.Length; i++) + { + var matches = regex.Matches(lines[i]); + if (matches.Count > 0) + { + var grps = matches[0].Groups; + outlines[i] + = $"{grps["pw"].Value}: {lines[i]}"; + } + else + { + outlines[i] = $"--------: {lines[i]}"; + } + } + + return outlines; + } +} diff --git a/exercises/concept/regular-expressions/.meta/config.json b/exercises/concept/regular-expressions/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/regular-expressions/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/regular-expressions/.meta/design.md b/exercises/concept/regular-expressions/.meta/design.md new file mode 100644 index 0000000000..8a219eea22 --- /dev/null +++ b/exercises/concept/regular-expressions/.meta/design.md @@ -0,0 +1,23 @@ +## Learning objectives + +- Know how to use regular expressions with `Regex` in C#. +- Know how to identify the presence of a pattern in a string. +- Know how to "capture" and replace text identified by patterns. +- Know how to use the `Options` property of `Regex`. +- Know that search performance can be enhanced by compiling `Regex` (discussion only) + +## Out of scope + +- Intermediate and advanced regular expression patterns. + +## Concepts + +- `regular-expressions` as they are handled in C# and .NET. + +## Prerequisites + +- `strings` +- `arrays` +- `for-loops` +- `verbatim-strings` +- `string-interpolation` diff --git a/exercises/concept/regular-expressions/RegularExpressions.cs b/exercises/concept/regular-expressions/RegularExpressions.cs new file mode 100644 index 0000000000..3ce3fb8a74 --- /dev/null +++ b/exercises/concept/regular-expressions/RegularExpressions.cs @@ -0,0 +1,30 @@ +using System; +using System.Text.RegularExpressions; + +public class LogParser +{ + public bool IsMatch(string text) + { + throw new NotImplementedException($"Please implement the LogParser.IsMatch() method"); + } + + public string[] SplitLogLine(string text) + { + throw new NotImplementedException($"Please implement the LogParser.SplitLogLine() method"); + } + + public int CountQuotedPasswords(string lines) + { + throw new NotImplementedException($"Please implement the LogParser.CountQuotedPasswords() method"); + } + + public string RemoveEndOfLineText(string line) + { + throw new NotImplementedException($"Please implement the LogParser.RemoveEndOfLineText() method"); + } + + public string[] ListLinesWithPasswords(string[] lines) + { + throw new NotImplementedException($"Please implement the LogParser.ListLinesWithPasswords() method"); + } +} diff --git a/exercises/concept/regular-expressions/RegularExpressions.csproj b/exercises/concept/regular-expressions/RegularExpressions.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/regular-expressions/RegularExpressions.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/regular-expressions/RegularExpressionsTests.cs b/exercises/concept/regular-expressions/RegularExpressionsTests.cs new file mode 100644 index 0000000000..3e8254f80a --- /dev/null +++ b/exercises/concept/regular-expressions/RegularExpressionsTests.cs @@ -0,0 +1,77 @@ +using System; +using Xunit; + +public class RegularExpressionTests +{ + [Fact] + public void IsMatch_match() + { + var lp = new LogParser(); + Assert.True(lp.IsMatch("[INF] My Message")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void IsMatch_no_match() + { + var lp = new LogParser(); + Assert.False(lp.IsMatch("bad start to [INF] Message")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void SplitLogLine() + { + var lp = new LogParser(); + Assert.Equal(new string[] {"section 1", "section 2", "section 3"}, lp.SplitLogLine("section 1<^>section 2<--->section 3")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void SplitLogLine_Empty() + { + var lp = new LogParser(); + Assert.Equal(new string[] {string.Empty}, lp.SplitLogLine(string.Empty)); + } + + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AreQuotedPasswords() + { + var lp = new LogParser(); + string[] lines = + { + string.Empty, + "[INF] passWord", + "\"passWord\"", + "[INF] The message \"Please reset your password\" was ignored by the user" + }; + Assert.Equal(2, lp.CountQuotedPasswords(string.Join(Environment.NewLine, lines))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void RemoveEndOfLineText() + { + var lp = new LogParser(); + string input = "[INF] end-of-line23033 Network Falure end-of-line27"; + Assert.Equal("[INF] Network Falure ", lp.RemoveEndOfLineText(input)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ListLinesWithPasswords() + { + var lp = new LogParser(); + string[] lines = + { + "[INF] passWordaa", + "passWord mysecret", + "[INF] password KeyToTheCastle for nobody", + "[INF] password password123 for everybody" + }; + string[] expected = + { + "passWordaa: [INF] passWordaa", + "--------: passWord mysecret", + "--------: [INF] password KeyToTheCastle for nobody", + "password123: [INF] password password123 for everybody" + }; + Assert.Equal(expected, lp.ListLinesWithPasswords(lines)); + } +} From 71056985afb6068180d5f15a80d4b0abb064e6f9 Mon Sep 17 00:00:00 2001 From: Mike May Date: Mon, 13 Jul 2020 02:03:14 -0400 Subject: [PATCH 171/327] Update instructions.md copy/paste error --- exercises/concept/time/.docs/instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/time/.docs/instructions.md b/exercises/concept/time/.docs/instructions.md index 945ca2016c..f19b5b5778 100644 --- a/exercises/concept/time/.docs/instructions.md +++ b/exercises/concept/time/.docs/instructions.md @@ -67,7 +67,7 @@ If a bad format is entered then a `DateTime` with a value of 1/1/1 should be ret ```csharp Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.London); -// => {2020, 3, 30, 13, 45, 0} +// => {2019, 11, 25, 13, 45, 0} Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.NewYork); // => {1, 1, 1, 0, 0, 0} ``` From 18003068ef31cf29aae9b5e7a241979cafd4b229 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 14 Jul 2020 09:28:10 +0200 Subject: [PATCH 172/327] Add after note in design.md document --- exercises/concept/basics/.meta/design.md | 48 ++++++++++++------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index 7102452fe9..c25b0ffcc1 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -1,32 +1,32 @@ ## Learning objectives -- Know what a variable is. -- Know how to define a variable. -- Know how to update a variable. -- Know how to use type inference for variables. -- Know how to define a method. -- Know how to return a value from a method. -- Know how to call a method. -- Know that methods must be defined in classes. -- Know about the `public` access modifier. -- Know about the `static` modifier. -- Know how to define an integer. -- Know how to use mathematical operators on integers. -- Know how to define single- and multiline comments. +- Know what a variable is +- Know how to define a variable +- Know how to update a variable +- Know how to use type inference for variables +- Know how to define a method +- Know how to return a value from a method +- Know how to call a method +- Know that methods must be defined in classes +- Know about the `public` access modifier +- Know about the `static` modifier (only in `after.md`) +- Know how to define an integer +- Know how to use mathematical operators on integers +- Know how to define single- and multiline comments ## Out of scope -- Naming rules for identifiers. -- Generic values. -- Memory and performance characteristics. -- Method overloads. -- Nested methods. -- Lambda's. -- Named parameters. -- Optional parameters. -- Classes. -- Organizing methods in namespaces. -- Visibility. +- Naming rules for identifiers +- Generic values +- Memory and performance characteristics +- Method overloads +- Nested methods +- Lambda's +- Named parameters +- Optional parameters +- Classes +- Organizing methods in namespaces +- Visibility ## Concepts From de9b7b5af7416b31d151d600a53d92276868b4f8 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 14 Jul 2020 07:14:22 -0400 Subject: [PATCH 173/327] overflow new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * overflow copied from old branch after repo snafu * overflow corrected code examples * overflow corrected code examples * overflow corrected code examples * overflow corrected code examples * Apply suggestions from code review Co-authored-by: Erik Schierboom * overflow finalizing PR * overflow finalizing PR * Apply suggestions from code review Co-authored-by: Erik Schierboom * review points * overflow added config.json Co-authored-by: Erik Schierboom --- exercises/concept/overflow/.docs/after.md | 57 ++++++++++++++++++ exercises/concept/overflow/.docs/hints.md | 30 ++++++++++ .../concept/overflow/.docs/instructions.md | 59 +++++++++++++++++++ .../concept/overflow/.docs/introduction.md | 21 +++++++ exercises/concept/overflow/.meta/Example.cs | 44 ++++++++++++++ exercises/concept/overflow/.meta/config.json | 22 +++++++ exercises/concept/overflow/.meta/design.md | 20 +++++++ exercises/concept/overflow/Overflow.cs | 19 ++++++ exercises/concept/overflow/Overflow.csproj | 13 ++++ exercises/concept/overflow/OverflowTests.cs | 42 +++++++++++++ 10 files changed, 327 insertions(+) create mode 100644 exercises/concept/overflow/.docs/after.md create mode 100644 exercises/concept/overflow/.docs/hints.md create mode 100644 exercises/concept/overflow/.docs/instructions.md create mode 100644 exercises/concept/overflow/.docs/introduction.md create mode 100644 exercises/concept/overflow/.meta/Example.cs create mode 100644 exercises/concept/overflow/.meta/config.json create mode 100644 exercises/concept/overflow/.meta/design.md create mode 100644 exercises/concept/overflow/Overflow.cs create mode 100644 exercises/concept/overflow/Overflow.csproj create mode 100644 exercises/concept/overflow/OverflowTests.cs diff --git a/exercises/concept/overflow/.docs/after.md b/exercises/concept/overflow/.docs/after.md new file mode 100644 index 0000000000..27f8730aa9 --- /dev/null +++ b/exercises/concept/overflow/.docs/after.md @@ -0,0 +1,57 @@ +The exercise shows the behavior of various numeric types when they overflow, i.e. when their capacity is insufficient to contain the value resulting from a computation such as an arithmetic operation or cast. + +- unsigned [integers][integral-numeric-types] (`byte`, `ushort`, `uint`, `ulong`) will wrap around to zero (the type's maximum value + 1 acts as a modulus) unless [broadly speaking][checked-compiler-setting] they appear within a [`checked`][checked-and-unchecked] block in which case an instance of `OverflowException` is thrown. `int` and `long` will behave similarly except that they wrap around to `int.MinValue` and `long.minValue` respectively. + +```csharp +int one = 1; +checked +{ + int expr = int.MaxValue + one; // overflow exception is thrown +} + +// or + +int expr2 = checked(int.MaxValue + one); // overflow exception is thrown +``` + +- If a literal expression would cause the variable to which it is assigned to overflow then a compile-time error occurs. +- the `checked` state applies only to expressions directly in the block. Overflow states in called functions are not caught. +- [`float` and `double`][floating-point-numeric-types] types will adopt a state of _infinity_ that can be tested wtih `float.IsInfinity()` etc. + +```csharp +double d = double.MaxValue; +d *= 2d; +Double.IsFinite(d) +// => false +``` + +- Numbers of type [`decimal`][floating-point-numeric-types] will cause an instance of `OverflowException` to be thrown. +- There is a corresponding `unchecked` keyword for circumstances where you want to reverse the effect of `unchecked` inside a `checked` block or when the compiler setting has been used. + +Overflows that occur without an exception being thrown can be problematic because it's generally true that the earlier an error condition can be reported the better. + +Problems with overflows for `int` and `float` can be mitigated by assigning the result to a variable of type `long`, `decimal` or `double`. + +If large integers are essential to your code then using the [`BigInteger`][big-integer] type is an option. + +Naturally there are occasions on which it is legitimate to allow an integer to wrap around particularly in the case of unsigned values. A classic case is that of hash codes that use the width of the integer as a kind of modulo. + +You will usually find in code bases that there is often no check where an `uint` or a `ulong` is used as an identifier because it is considered more trouble than it's worth. This also applies where it is evident from the domain that no very large values will be involved. But, look at [this][computerphile-gangnam-style] for a cautionary tale. + +- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. +- [Floating-point numeric types][floating-point-numeric-types]: overview of the floating-point numeric types. +- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. +- [Checked and unchecked arithmetic][checked-and-unchecked]: introduction to overflows +- [`checked` keyword][checked-keyword]: `checked` keyword reference. +- [`unchecked` keyword][unchecked-keyword]: `unchecked` keyword reference. +- [Computerphile: How Gangnam Style broke YouTube][computerphile-gangnam-style] + +[computerphile-gangnam-style]: https://www.youtube.com/watch?v=vA0Rl6Ne5C8 +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[checked-and-unchecked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked +[checked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked +[unchecked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unchecked +[checked-compiler-setting]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/checked-compiler-option +[big-integer]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netcore-3.1 diff --git a/exercises/concept/overflow/.docs/hints.md b/exercises/concept/overflow/.docs/hints.md new file mode 100644 index 0000000000..3ae80c9f40 --- /dev/null +++ b/exercises/concept/overflow/.docs/hints.md @@ -0,0 +1,30 @@ +## 1. Print bank note denominations + +- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. +- [Checked and unchecked arithmetic][checked-and-unchecked]: introduction to overflows +- [`checked` keyword][checked-keyword]: `checked` keyword reference. +- [`OverflowException`][overflow-exception]: overflow exception + +## 2. Display GDP for Hyperia + +- [Floating-point numeric types][floating-point-numeric-types]: overview of the floating-point numeric types. +- This article discusses the [`float`][single] type. + +## 3. Display Chief Economist's salary + +- [Floating-point numeric types][floating-point-numeric-types]: overview of the floating-point numeric types. +- [`OverflowException`][overflow-exception]: overflow exception +- [`Decimal`][decimal]: the decimal type + +[computerphile-gangnam-style]: https://www.youtube.com/watch?v=vA0Rl6Ne5C8 +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[checked-and-unchecked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked +[checked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked +[unchecked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unchecked +[checked-compiler-setting]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/checked-compiler-option +[big-integer]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netcore-3.1 +[single]: https://docs.microsoft.com/en-us/dotnet/api/system.single?view=netcore-3.1 +[overflow-exception]: https://docs.microsoft.com/en-us/dotnet/api/system.overflowexception?view=netcore-3.1 +[decimal]: https://docs.microsoft.com/en-us/dotnet/api/system.decimal?view=netcore-3.1 diff --git a/exercises/concept/overflow/.docs/instructions.md b/exercises/concept/overflow/.docs/instructions.md new file mode 100644 index 0000000000..8026124c0e --- /dev/null +++ b/exercises/concept/overflow/.docs/instructions.md @@ -0,0 +1,59 @@ +The country of Hyperia has its problems. In particular, inflation is out of control. You have been flown in to take up a contract at the central bank. + +## 1. Print bank note denominations + +To simplify administration internally the central bank has split each denomination into parts, a _base_ that remains relatively unchanged, and a _multiplier_ (the same for all denominations) which can be changed yearly or weekly or even daily. + +When printed the denominations on bank notes are the product of _base_ and _multiplier_. + +By the time this system was introduced the minimum bank note already had a denomination of 10,000,000. The table below shows the position (for the first 3 denominations) when the system was first introduced. Things have got much worse since then and not only does the multiplier change so does the base. + +| Base | Multiplier | Denomination | +| ------- | ---------- | ------------ | +| 10,000 | 1,000 | 10,000,000 | +| 50,000 | 1,000 | 50,000,000 | +| 100,000 | 1,000 | 100,000,000 | +| ... | 1,000 | ... | + +In summary, this means that _denomination_ = _base_ \* _multiplier_. + +Please implement the method `CentralBank.DisplayDenomination()` which takes the base and multiplier and returns a string of their product (base \* multiplier). The numeric string returned should not be formatted. + +If the multiplication operation causes an overflow then the string, `"*** Too Big ***"`, should be returned. + +```csharp +CentralBank.DisplayDenomination(10000L, 1000L); +// => "10000000" +CentralBank.DisplayDenomination(long.MaxValue / 2, 10000L); +// => "*** Too Big ***" +``` + +## 2. Display GDP for Hyperia + +The central bank uses the same multiplier approach to recording GDP internally. Statistics are recorded in a base denomination and then scaled up using the multiplier. + +Please implement the method `CentralBank.DisplayGDP()` which takes the base GDP and the current multiplier and returns the GDP as a string. + +If the GDP cannot be calculated then `"*** Too Big ***"` is returned. + +```csharp +CentralBank.DisplayGDP(555f, 10000f); +// => "555000000" +CentralBank.DisplayGDP(float.MaxValue / 2, 10000f); +// => "*** Too Big ***" +``` + +## 3. Display Chief Economist's salary + +Your boss at the bank wants to make sure there will be no problems at payroll time. + +Implement the `CentralBank.DisplayChiefEconomistSalary()` method that takes a salary expressed in base units (as above) and a multiplier and returns a string containing the product. + +If the salary cannot be calculated then `"*** Much Too Big ***"` is returned. + +```csharp +CentralBank.DisplayChiefEconomistSalary(555000m, 10000m); +// => "5550000000" +CentralBank.DisplayChiefEconomistSalary(555000m, decimal.MaxValue / 2L); +// => "*** Much Too Big ***" +``` diff --git a/exercises/concept/overflow/.docs/introduction.md b/exercises/concept/overflow/.docs/introduction.md new file mode 100644 index 0000000000..a2313bf95e --- /dev/null +++ b/exercises/concept/overflow/.docs/introduction.md @@ -0,0 +1,21 @@ +Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type. + +Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances. + +The behavior of integer computations can be modified by using the `checked` keyword. When an overflow occurs within a `checked` block an instance of `OverflowException` is thrown. + +```csharp +int one = 1; +checked +{ + int expr = int.MaxValue + one; // OverflowException is thrown +} + +// or + +int expr2 = checked(int.MaxValue + one); // OverflowException is thrown +``` + +Expressions of type `float` and `double` will take a special value of infinity. + +Expressions of type `decimal` will throw an instance of `OverflowException`. diff --git a/exercises/concept/overflow/.meta/Example.cs b/exercises/concept/overflow/.meta/Example.cs new file mode 100644 index 0000000000..0ce2cff345 --- /dev/null +++ b/exercises/concept/overflow/.meta/Example.cs @@ -0,0 +1,44 @@ +using System; + +public static class CentralBank +{ + public static string DisplayDenomination(long @base, long multiplier) + { + try + { + checked + { + return (@base * multiplier).ToString(); + } + } + catch (OverflowException) + { + return "*** Too Big ***"; + } + } + + public static string DisplayGDP(float @base, float multiplier) + { + float gdp = @base * multiplier; + if (float.IsInfinity(gdp)) + { + return "*** Too Big ***"; + } + else + { + return gdp.ToString(); + } + } + + public static string DisplayChiefEconomistSalary(decimal salaryBase, decimal multiplier) + { + try + { + return (salaryBase * multiplier).ToString(); + } + catch (OverflowException) + { + return "*** Much Too Big ***"; + } + } +} diff --git a/exercises/concept/overflow/.meta/config.json b/exercises/concept/overflow/.meta/config.json new file mode 100644 index 0000000000..be058a23f7 --- /dev/null +++ b/exercises/concept/overflow/.meta/config.json @@ -0,0 +1,22 @@ +{ + "contributors": [ + { + "github_username": "ihid", + "exercism_username": "ihid" + }, + { + "github_username": "sleeplessbyte", + "exercism_username": "sleeplessbyte" + }, + { + "github_username": "saschamann", + "exercism_username": "saschamann" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/overflow/.meta/design.md b/exercises/concept/overflow/.meta/design.md new file mode 100644 index 0000000000..eb815702e9 --- /dev/null +++ b/exercises/concept/overflow/.meta/design.md @@ -0,0 +1,20 @@ +## Learning objectives + +- Explain integral number overflows. +- Explain floating-point number overflows. +- Know how to use `checked` and `unchecked` to deal with overflows. + +## Out of scope + +- BigInteger + +## Concepts + +- `overflows`: explain integral number overflows; explain floating-point number overflows; know how to use `checked` and `unchecked` to deal with overflows. + +## Prequisites + +- `integral-numbers`: know about the integral number types. +- `floating-point-numbers`: know about the floating-point number types. +- `exceptions`: explain how an `OverflowException` is thrown when using checked arithmetic. +- `strings`: numbers are converted to strings. diff --git a/exercises/concept/overflow/Overflow.cs b/exercises/concept/overflow/Overflow.cs new file mode 100644 index 0000000000..c83122b9bf --- /dev/null +++ b/exercises/concept/overflow/Overflow.cs @@ -0,0 +1,19 @@ +using System; + +public static class CentralBank +{ + public static string DisplayDenomination(long @base, long multiplier) + { + throw new NotImplementedException($"Please implement the (static) CentralBank.DisplayDenomination() method"); + } + + public static string DisplayGDP(float @base, float multiplier) + { + throw new NotImplementedException($"Please implement the (static) CentralBank.DisplayGDP() method"); + } + + public static string DisplayChiefEconomistSalary(decimal salaryBase, decimal multiplier) + { + throw new NotImplementedException($"Please implement the (static) CentralBank.DisplayChiefEconomistSalary() method"); + } +} diff --git a/exercises/concept/overflow/Overflow.csproj b/exercises/concept/overflow/Overflow.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/overflow/Overflow.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/overflow/OverflowTests.cs b/exercises/concept/overflow/OverflowTests.cs new file mode 100644 index 0000000000..19e8e17633 --- /dev/null +++ b/exercises/concept/overflow/OverflowTests.cs @@ -0,0 +1,42 @@ +using System; +using Xunit; + +public class OverflowTests +{ + [Fact] + public void DisplayDenomination_good() + { + Assert.Equal("10000000", CentralBank.DisplayDenomination(10000L, 1000L)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplayDenomination_bad() + { + Assert.Equal("*** Too Big ***", CentralBank.DisplayDenomination( long.MaxValue / 2L, 10000L)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplayGDP_good() + { + Assert.Equal("5550000", CentralBank.DisplayGDP(555f, 10000f)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplayGDP_bad() + { + Assert.Equal("*** Too Big ***", CentralBank.DisplayGDP(float.MaxValue / 2L, 10000f)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySalary_good() + { + Assert.Equal("5550000000", CentralBank.DisplayChiefEconomistSalary(555000m, 10000m)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplaySalary_bad() + { + Assert.Equal("*** Much Too Big ***", CentralBank.DisplayChiefEconomistSalary(555000m, + decimal.MaxValue / 2L)); + } +} From 1b3816e0a1fa8f521b94c7939622f4e642573f54 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 14 Jul 2020 07:34:24 -0400 Subject: [PATCH 174/327] resource-lifetime new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * resource-lifetime copied from old branch after repo snafu * resource-lifetime cosmetic * resource-lifetime cosmetic * resource-lifetime cosmetic * Apply suggestions from code review Co-authored-by: Erik Schierboom * resource-lifetime WIP * resource-lifetime towards final PR * resource-lifetime towards final PR * resource-lifetime towards final PR * resource-lifetime final PR * Apply suggestions from code review Co-authored-by: Erik Schierboom * resource-lifetime updated config.json * resource-lifetime review points Co-authored-by: Erik Schierboom --- .../concept/resource-lifetime/.docs/after.md | 77 ++++++++++ .../concept/resource-lifetime/.docs/hints.md | 14 ++ .../resource-lifetime/.docs/instructions.md | 42 ++++++ .../resource-lifetime/.docs/introduction.md | 30 ++++ .../resource-lifetime/.meta/Example.cs | 36 +++++ .../resource-lifetime/.meta/config.json | 8 ++ .../concept/resource-lifetime/.meta/design.md | 17 +++ .../resource-lifetime/ResourceLifetime.cs | 21 +++ .../resource-lifetime/ResourceLifetime.csproj | 13 ++ .../ResourceLifetimeTests.cs | 133 ++++++++++++++++++ 10 files changed, 391 insertions(+) create mode 100644 exercises/concept/resource-lifetime/.docs/after.md create mode 100644 exercises/concept/resource-lifetime/.docs/hints.md create mode 100644 exercises/concept/resource-lifetime/.docs/instructions.md create mode 100644 exercises/concept/resource-lifetime/.docs/introduction.md create mode 100644 exercises/concept/resource-lifetime/.meta/Example.cs create mode 100644 exercises/concept/resource-lifetime/.meta/config.json create mode 100644 exercises/concept/resource-lifetime/.meta/design.md create mode 100644 exercises/concept/resource-lifetime/ResourceLifetime.cs create mode 100644 exercises/concept/resource-lifetime/ResourceLifetime.csproj create mode 100644 exercises/concept/resource-lifetime/ResourceLifetimeTests.cs diff --git a/exercises/concept/resource-lifetime/.docs/after.md b/exercises/concept/resource-lifetime/.docs/after.md new file mode 100644 index 0000000000..6b029325c0 --- /dev/null +++ b/exercises/concept/resource-lifetime/.docs/after.md @@ -0,0 +1,77 @@ +We discussed in (TODO cross-ref-tba) how the `IDispoable` interface helps signal to callers of a class that there are resources or program state that need releasing or resetting in a timely fashion when the object in question is no longer required. In this exercise we have introduced some syntactic sugar, with the `using` keyword, that makes the code less verbose and less likely that significant calls will be omitted. + +`using` can be seen as replacing [`try/finally`][try-finally] for some use cases. + +```csharp +File file = null; +try +{ + file = new File("myStuff.txt"); + file.Write("more stuff"); +} +finally +{ + file.Dispose(); +} +``` + +This syntax is replaced with the more compact and foolproof: + +```csharp +using (var file = new File("myStuff.txt") +{ + file.Write("more stuff"); +} +``` + +Note that multiple resources can be conveniently combined following standard rules for single line blocks: + +```csharp +using (var file = new File("mystuff.txt") +using (var fileWriter = new StreamWriter(file) +{ + ... +} +``` + +In C# 8 the following variation has been introduced where the `using` statement comes at the start of a block: + +```csharp +using var file = new File("myStuff.txt"); +file.Write("more stuff"); +``` + +This allows you to have multiple disposable objects in the same block and to more naturally handle [`try/catch`][try-catch]: + +```csharp +using var fileIn = new File("myStuff.txt"); +using var fileOut = new File("yourStuff.txt"); +try +{ + var stuff = fileIn.Read(); + fileOut.Write(stuff); +} +catch (Exception) +{ + LogStuff(); +} +``` + +The rules related to how the `using` keyword can be used and with instances of what sort of types are detailed [here][using-statement]. + +#### Note for Java Developers + +Java developers may recognize this as an analog of the [_automatic resource management_][automatic-resource-management] mechanism introduced in Java 7. They are very similar. Java's syntax, which repurposes `try` has the advantage of incorporating `catch` blocks more naturally than does C#'s `using`. + +#### Versions + +Note that the more flexible version of `using` where it does not have its own syntactic block was introduced in C# 8 so you may need to check if the code base you are working on is using C# 8 or later. + +#### Reference + +[using statement][using-statement] documentation describes how and when to use the `using` keyword. + +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[automatic-resource-management]: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html +[try-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally +[try-catch]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-the-try-catch-block-to-catch-exceptions diff --git a/exercises/concept/resource-lifetime/.docs/hints.md b/exercises/concept/resource-lifetime/.docs/hints.md new file mode 100644 index 0000000000..dd74515a78 --- /dev/null +++ b/exercises/concept/resource-lifetime/.docs/hints.md @@ -0,0 +1,14 @@ +## General + +- [using statement][using-statement] documentation describes how and when to use the `using` keyword. + +## 1. Write to the database + +- Consider the various methods on the database, and the states that the database transitions to with each one. + +## 2. Write to the database and return an indication to the caller of whether the write operation was successful + +- Use of [`try/catch`][try-catch] is necessary in this case. + +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[try-catch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch diff --git a/exercises/concept/resource-lifetime/.docs/instructions.md b/exercises/concept/resource-lifetime/.docs/instructions.md new file mode 100644 index 0000000000..6f4e809c5b --- /dev/null +++ b/exercises/concept/resource-lifetime/.docs/instructions.md @@ -0,0 +1,42 @@ +You are back working on the ORM (Object Relationship Mapping) system introduced in (TODO cross-reference-tba). + +Our ORM usage analysis shows that 95% of transactions are executed from within one calling method, and it has been decided that it would be more appropriate to have a single ORM method that opened, wrote and committed a transaction. + +The database has the following instance methods: + +- `Database.BeginTransaction()` starts a transaction on the database. +- `Database.Write(string data)` writes data to the database within the transaction. If it receives bad data an exception will be thrown. An attempt to call this method without `BeginTransction()` having been called will cause an exception to be thrown. If successful the internal state of the database will change to `DataWritten`. +- `Database.Commit()` commits the transaction to the database. It may throw an exception if it can't close the transaction or if `Database.BeginTransaction()` had not been called. +- A call to`Databse.Dispose()` will clean up the database if an exception is thrown during a transaction. This will change the state of the database to `Closed`. + +## 1. Write to the database + +Implement the `Orm.Write()` method to begin a database transaction, write the data passed in and commit the transaction. All exceptions including `InvalidOperationException` should be allowed to pass to the caller without logging or any other intervention. + +```csharp +Database db = new Database(); +Orm orm = new Orm(db); +orm.Write("good write"); +// => database has an internal state of State.Closed +orm.Write("bad write"); +// => an exception is thrown but database is left with an internal state of State.Closed +orm.Write("bad commit"); +// => an exception is thrown but database is left with an internal state of State.Closed +``` + +## 2. Write to the database and return an indication of whether the write was successful to the caller + +It has been a few months since `Orm.Write()` was introduced and there is division in the team. Many developers would like the _ORM_ to handle errors when exceptions are thrown and simply return an indication of success to the caller. + +Please implement the `Orm.WriteSafely()` method to begin a database transaction, write the data passed in and commit the transaction (as above). It should return `true` if the _write_ was successful, otherwise `false`. Do not attempt to log the exception. + +```csharp +Database db = new Database(); +Orm orm = new Orm(db); +orm.WriteSafely("good write"); +// => true +orm.WriteSafely("bad write"); +// => false +orm.WriteSafely("bad commit"); +// => false +``` diff --git a/exercises/concept/resource-lifetime/.docs/introduction.md b/exercises/concept/resource-lifetime/.docs/introduction.md new file mode 100644 index 0000000000..77a8122259 --- /dev/null +++ b/exercises/concept/resource-lifetime/.docs/introduction.md @@ -0,0 +1,30 @@ +You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations. + +There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement. + +```csharp +using (var file = new File("my_secrets")) +{ + file.WriteSecret("xxxxxxx"); +} +``` + +In the above example the file system resources associated with `file` will be released back to the operating system when the `using` block is exited. + +For the pattern to work the variable in the using statement must be a reference type that implements the `IDisposable` interface and must release resources/reset program state in its `Dispose()` method. + +C# 8 introduces a refinement to the pattern. A using statement can placed at the beginning of a block. + +```csharp +using var drawingResource = some_provided_or_newed_object; +try +{ + drawingResource.DrawSomething(); +} +catch (Exception) +{ + throw; +} +``` + +Java developers may recognize this as an analog of the _automatic resource management_ mechanism introduced in Java 7. diff --git a/exercises/concept/resource-lifetime/.meta/Example.cs b/exercises/concept/resource-lifetime/.meta/Example.cs new file mode 100644 index 0000000000..f0785012f0 --- /dev/null +++ b/exercises/concept/resource-lifetime/.meta/Example.cs @@ -0,0 +1,36 @@ +using System; + +public class Orm +{ + private Database database; + + public Orm(Database database) + { + this.database = database; + } + + public void Write(string data) + { + using (database) + { + database.Write(data); + database.EndTransaction(); + } + } + + public bool WriteSafely(string data) + { + using var db = database; + try + { + db.Write(data); + db.EndTransaction(); + + return true; + } + catch (InvalidOperationException) + { + return false; + } + } +} diff --git a/exercises/concept/resource-lifetime/.meta/config.json b/exercises/concept/resource-lifetime/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/resource-lifetime/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/resource-lifetime/.meta/design.md b/exercises/concept/resource-lifetime/.meta/design.md new file mode 100644 index 0000000000..bb6083837a --- /dev/null +++ b/exercises/concept/resource-lifetime/.meta/design.md @@ -0,0 +1,17 @@ +## Learning objectives + +- Know how to control a resource's lifetime with the `using` statement in C#. + +## Out of scope + +## Concepts + +- `resource-lifetime` as it is handled in C#. + +## Prerequisites + +- `resource-cleanup`: this exercise highlights the difference between the two approaches, + +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[analyzer]: https://github.com/exercism/csharp-analyzer +[representer]: https://github.com/exercism/csharp-representer diff --git a/exercises/concept/resource-lifetime/ResourceLifetime.cs b/exercises/concept/resource-lifetime/ResourceLifetime.cs new file mode 100644 index 0000000000..dfb10c6c3f --- /dev/null +++ b/exercises/concept/resource-lifetime/ResourceLifetime.cs @@ -0,0 +1,21 @@ +using System; + +public class Orm +{ + private Database database; + + public Orm(Database database) + { + this.database = database; + } + + public void Write(string data) + { + throw new NotImplementedException($"Please implement the Orm.Write() method"); + } + + public bool WriteSafely(string data) + { + throw new NotImplementedException($"Please implement the Orm.WriteSafely() method"); + } +} diff --git a/exercises/concept/resource-lifetime/ResourceLifetime.csproj b/exercises/concept/resource-lifetime/ResourceLifetime.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/resource-lifetime/ResourceLifetime.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/resource-lifetime/ResourceLifetimeTests.cs b/exercises/concept/resource-lifetime/ResourceLifetimeTests.cs new file mode 100644 index 0000000000..15c1023b64 --- /dev/null +++ b/exercises/concept/resource-lifetime/ResourceLifetimeTests.cs @@ -0,0 +1,133 @@ +using System; +using Xunit; + +public class ResourceLifetimeTests +{ + enum Exception + { + InvalidOperationExceptionThrown, + NoInvalidOperationExceptionThrown + } + [Fact] + public void Write_good() + { + var db = new Database(); + var orm = new Orm(db); + orm.Write("good write"); + Assert.Equal((Database.State.Closed, "good write"), + (Database.DbState, Database.lastData)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Write_bad() + { + Exception result = Exception.NoInvalidOperationExceptionThrown; + try + { + var db = new Database(); + var orm = new Orm(db); + orm.Write("bad write"); + } + catch (InvalidOperationException) + { + result = Exception.InvalidOperationExceptionThrown; + } + Assert.Equal((Exception.InvalidOperationExceptionThrown, Database.State.Closed, "bad write"), + (result, Database.DbState, Database.lastData)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Commit_bad() + { + Exception result = Exception.NoInvalidOperationExceptionThrown; + try + { + var db = new Database(); + var orm = new Orm(db); + orm.Write("bad commit"); + } + catch (InvalidOperationException) + { + result = Exception.InvalidOperationExceptionThrown; + } + Assert.Equal((Exception.InvalidOperationExceptionThrown, Database.State.Closed, "bad commit"), + (result, Database.DbState, Database.lastData)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CommitSafely_good() + { + var db = new Database(); + var orm = new Orm(db); + Assert.True(orm.WriteSafely("good write")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CommitSafely_bad_write() + { + var db = new Database(); + var orm = new Orm(db); + Assert.False(orm.WriteSafely("bad write")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CommitSafely_bad_commit() + { + var db = new Database(); + var orm = new Orm(db); + Assert.False(orm.WriteSafely("bad commit")); + } +} + +// **** please do not modify the Database class **** +public class Database : IDisposable +{ + public enum State {TransactionStarted, DataWritten, Invalid, Closed} + + public static State DbState { get; private set; } = State.Closed; + public static string lastData = string.Empty; + + public Database() + { + DbState = State.TransactionStarted; + } + + public void Write(string data) + { + if (DbState != State.TransactionStarted) + { + throw new InvalidOperationException(); + } + // this does something significant with the db transaction object + lastData = data; + if (data == "bad write") + { + DbState = State.Invalid; + throw new InvalidOperationException(); + } + + DbState = State.DataWritten; + } + + public void EndTransaction() + { + if (DbState != State.DataWritten && DbState != State.TransactionStarted) + { + throw new InvalidOperationException(); + } + // this does something significant to end the db transaction object + if (lastData == "bad commit") + { + DbState = State.Invalid; + throw new InvalidOperationException(); + } + + DbState = State.Closed; + } + + public void Dispose() + { + DbState = State.Closed; + } +} + From 76a20ffb14209fe020d48e4b81a437315121e67f Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 14 Jul 2020 08:47:07 -0400 Subject: [PATCH 175/327] Update hints.md --- exercises/concept/resource-lifetime/.docs/hints.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/resource-lifetime/.docs/hints.md b/exercises/concept/resource-lifetime/.docs/hints.md index dd74515a78..77d1206bd1 100644 --- a/exercises/concept/resource-lifetime/.docs/hints.md +++ b/exercises/concept/resource-lifetime/.docs/hints.md @@ -8,7 +8,7 @@ ## 2. Write to the database and return an indication to the caller of whether the write operation was successful -- Use of [`try/catch`][try-catch] is necessary in this case. +- Use of [`exceptions`][try-catch] is necessary in this case. [using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement [try-catch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch From 70ca5e4fa6ef9edc3d762febee4964a65b7e3031 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 14 Jul 2020 08:49:31 -0400 Subject: [PATCH 176/327] nested-types new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * nested-types initial commit * nested-types draft PR * nested-types typo * nested-types typo * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * Apply suggestions from code review Co-authored-by: Erik Schierboom * nested-types review points * nested-types added config.json Co-authored-by: Erik Schierboom --- exercises/concept/nested-types/.docs/after.md | 108 ++++++++++++++++++ exercises/concept/nested-types/.docs/hints.md | 19 +++ .../nested-types/.docs/instructions.md | 29 +++++ .../nested-types/.docs/introduction.md | 18 +++ .../concept/nested-types/.meta/Example.cs | 97 ++++++++++++++++ .../concept/nested-types/.meta/config.json | 8 ++ .../concept/nested-types/.meta/design.md | 20 ++++ exercises/concept/nested-types/NestedTypes.cs | 79 +++++++++++++ .../concept/nested-types/NestedTypes.csproj | 13 +++ .../concept/nested-types/NestedTypesTests.cs | 23 ++++ 10 files changed, 414 insertions(+) create mode 100644 exercises/concept/nested-types/.docs/after.md create mode 100644 exercises/concept/nested-types/.docs/hints.md create mode 100644 exercises/concept/nested-types/.docs/instructions.md create mode 100644 exercises/concept/nested-types/.docs/introduction.md create mode 100644 exercises/concept/nested-types/.meta/Example.cs create mode 100644 exercises/concept/nested-types/.meta/config.json create mode 100644 exercises/concept/nested-types/.meta/design.md create mode 100644 exercises/concept/nested-types/NestedTypes.cs create mode 100644 exercises/concept/nested-types/NestedTypes.csproj create mode 100644 exercises/concept/nested-types/NestedTypesTests.cs diff --git a/exercises/concept/nested-types/.docs/after.md b/exercises/concept/nested-types/.docs/after.md new file mode 100644 index 0000000000..b48de2b025 --- /dev/null +++ b/exercises/concept/nested-types/.docs/after.md @@ -0,0 +1,108 @@ +C# types can be defined within the scope of a class or struct. The enclosing type provides a kind name space. Access to the type is through the enclosing type with dot syntax. + +```csharp +class Outer +{ + public interface IInner {} + public enum EInner {} + public class CInner {} + public struct SInner {} +} + +var outer = new Outer(); +var inner = new Outer.CInner(); +``` + +#### Access levels + +Access levels can be applied to the inner types. For example if a class is `private` then it cannot be seen outside of the enclosing type's scope and of course instances cannot be seen or used outside the scope. + +The private members of the outer class are in scope for all the members of the inner class but only the non-private members of the inner class are in scope for the members of the outer class. In order to access the outer classes members the inner class has to be given an instance of the outer class. + +This can be seen in the following example: + +```csharp +class Outer +{ + public class InnerImpl + { + private Outer outer; + + public int Interesting = 42; + + public InnerImpl(Outer outer, int interesting) + { + this.outer = outer; + Interesting = interesting; + } + + } + + public InnerImpl Inner; + public Outer() + { + Inner = new InnerImpl(this, 42); + } +} + +var outer = new Outer(); +outer.Inner.Interesting +// => 42 +var inner = new Outer.InnerImpl(outer, 1729); +outer.Inner.Interesting +// => 1729 +``` + +#### Prevent independent instantiation + +There is a pattern to prevent an instantiable type being created outside the enclosing type. You expose a public interface but keep the implementing class private. + +```csharp +class Outer +{ + public interface IInner + { + void DoSomething(); + } + + private class InnerImpl : IInner + { + private Outer outer; + public InnerImpl(Outer outer) + { + this.outer = outer; + } + public void DoSomething() + { + outer.DoSomethingElse(); + } + } + + public IInner Inner; + + public Outer() + { + Inner = new InnerImpl(this); + } + private void DoSomethingElse() + { + } +} + +var outer = new Outer(); +outer.Inner.DoSomething(); + +// NOT var inner = new Outer.Inner(outer); +``` + +#### Note for Java developers + +C#'s nested classes are a cross between Java's static nested classes and inner classes. In C# private members of the enclosing class are in scope for members of the nested class but there is no special syntax for instantiating them and linking them to an instance of the enclosing class. You have to use some variation of the pattern illustrated in the examples above. + +C# does have static nested classes, but these are simply enclosed classes with static behavior. + +#### Reference + +This documentation of [nested types][nested-types] details the syntax. + +[nested-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types diff --git a/exercises/concept/nested-types/.docs/hints.md b/exercises/concept/nested-types/.docs/hints.md new file mode 100644 index 0000000000..2180486ec5 --- /dev/null +++ b/exercises/concept/nested-types/.docs/hints.md @@ -0,0 +1,19 @@ +## General + +- This documentation of [nested types][nested-types] details the syntax. + +## 1. Separate concerns between the car itself and the telemetry system + +- Members of `RemoteControlCar` suffixed with "\_Telemetry" could be moved to a separate class. + +## 2. Prevent other code taking too many dependencies on the Telemetry type + +- [Interfaces][interfaces] are the secret sauce here. + +## 3. Prevent other code from taking dependencies on the Speed struct + +- Give some consideration to [access levels][access-levels]. + +[nested-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types +[interfaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ +[access-levels]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers diff --git a/exercises/concept/nested-types/.docs/instructions.md b/exercises/concept/nested-types/.docs/instructions.md new file mode 100644 index 0000000000..01fa43484a --- /dev/null +++ b/exercises/concept/nested-types/.docs/instructions.md @@ -0,0 +1,29 @@ +Some "other" developers have been working on the remote control car project (TODO cross-ref-tba). You have been called in to clean up the code. + +## 1. Separate concerns between the car itself and the telemetry system + +Refactor the `RemoteControlCar` class to move to separate out telemetry methods and properties. + +```csharp +var car = new RemoteControlCar(); +car.Telemetry.Calibrate(); +car.Telemetry.SelfTest(); +car.Telemetry.ShowSponsor("Walker Industries Inc."); +car.CurrentSponsor +// => "Walker Industries Inc." +car.Telemetry.SetSpeed(100, "cpm"); +car.GetSpeed() +// => "100 centimeters per second" +``` + +## 2. Prevent other code taking too many dependencies on the Telemetry type + +Ensure that the `Telemetry` instance cannot be created outside the scope of the car. + +## 3. Prevent other code from taking dependencies on the Speed struct + +Ensure that the `Speed` struct cannot be used outside the scope of the `RemoteControlCar` class. + +## 4. Prevent other code from taking dependencies on the SpeedUnits enum + +Ensure that the `SpeedUnits` enum cannot be used outside the scope of the `RemoteControlCar` class. diff --git a/exercises/concept/nested-types/.docs/introduction.md b/exercises/concept/nested-types/.docs/introduction.md new file mode 100644 index 0000000000..1edafdd14b --- /dev/null +++ b/exercises/concept/nested-types/.docs/introduction.md @@ -0,0 +1,18 @@ +C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax. + +```csharp +class Outer +{ + public interface IInner {} + public enum EInner {} + public class CInner {} + public struct SInner {} +} + +var outer = new Outer(); +var inner = new Outer.CInner(); +``` + +You can set access levels for inner types. + +Private members of the outer type are in scope for members of the inner type but not vice versa. diff --git a/exercises/concept/nested-types/.meta/Example.cs b/exercises/concept/nested-types/.meta/Example.cs new file mode 100644 index 0000000000..0fd5986a81 --- /dev/null +++ b/exercises/concept/nested-types/.meta/Example.cs @@ -0,0 +1,97 @@ +public class RemoteControlCar +{ + private enum SpeedUnits + { + MetersPerSecond, + CentimetersPerSecond + } + + private struct Speed + { + public decimal Amount { get; } + public SpeedUnits SpeedUnits { get; } + + public Speed(decimal amount, SpeedUnits speedUnits) + { + Amount = amount; + SpeedUnits = speedUnits; + } + + public override string ToString() + { + string unitsString = "meters per second"; + if (SpeedUnits == SpeedUnits.CentimetersPerSecond) + { + unitsString = "centimeters per second"; + } + + return Amount + " " + unitsString; + } + } + + public interface ITelemetry + { + void Calibrate(); + bool SelfTest(); + void ShowSponsor(string sponsorName); + void SetSpeed(decimal amount, string units); + } + + private class TelemetryImpl : ITelemetry + { + private RemoteControlCar thisCar; + public TelemetryImpl(RemoteControlCar car) + { + thisCar = car; + } + public void Calibrate() + { + } + + public bool SelfTest() + { + return true; + } + + public void ShowSponsor(string sponsorName) + { + thisCar.SetSponsor(sponsorName); + } + + public void SetSpeed(decimal amount, string unitsString) + { + SpeedUnits speedUnits = SpeedUnits.MetersPerSecond; + if (unitsString == "cps") + { + speedUnits = SpeedUnits.CentimetersPerSecond; + } + thisCar.SetSpeed(new Speed(amount, speedUnits)); + } + } + + public ITelemetry Telemetry { get; } + public string CurrentSponsor { get; private set; } + + private Speed currentSpeed; + + public RemoteControlCar() + { + Telemetry = new TelemetryImpl(this); + } + + public string GetSpeed() + { + return currentSpeed.ToString(); + } + + private void SetSponsor(string sponsorName) + { + CurrentSponsor = sponsorName; + + } + + private void SetSpeed(Speed speed) + { + currentSpeed = speed; + } +} diff --git a/exercises/concept/nested-types/.meta/config.json b/exercises/concept/nested-types/.meta/config.json new file mode 100644 index 0000000000..315b869235 --- /dev/null +++ b/exercises/concept/nested-types/.meta/config.json @@ -0,0 +1,8 @@ +{ + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/nested-types/.meta/design.md b/exercises/concept/nested-types/.meta/design.md new file mode 100644 index 0000000000..d71dd5640c --- /dev/null +++ b/exercises/concept/nested-types/.meta/design.md @@ -0,0 +1,20 @@ +## Learning objectives + +- Know how and why to use nested classes in C#. +- Know how and why to use nested structs (discussion only). + +## Out of scope + +- `namespaces` + +## Concepts + +- `nested-types` + +## Prerequisites + +- `classes` +- `structs` +- `enums` +- `properties` +- `interfaces` diff --git a/exercises/concept/nested-types/NestedTypes.cs b/exercises/concept/nested-types/NestedTypes.cs new file mode 100644 index 0000000000..75c22ddfa3 --- /dev/null +++ b/exercises/concept/nested-types/NestedTypes.cs @@ -0,0 +1,79 @@ +public class RemoteControlCar +{ + public string CurrentSponsor { get; private set; } + + private Speed currentSpeed; + + // TODO encapsulate the methods suffixed with "_Telemetry" in their own class + // dropping the suffix from the method name + public void Calibrate_Telementry() + { + + } + + public bool SelfTest_Telemetry() + { + return true; + } + + public void ShowSponsor_Telemetry(string sponsorName) + { + SetSponsor(sponsorName); + } + + public void SetSpeed_Telemetry(decimal amount, string unitsString) + { + SpeedUnits speedUnits = SpeedUnits.MetersPerSecond; + if (unitsString == "cps") + { + speedUnits = SpeedUnits.CentimetersPerSecond; + } + + SetSpeed(new Speed(amount, speedUnits)); + } + + public string GetSpeed() + { + return currentSpeed.ToString(); + } + + private void SetSponsor(string sponsorName) + { + CurrentSponsor = sponsorName; + + } + + private void SetSpeed(Speed speed) + { + currentSpeed = speed; + } +} + +public enum SpeedUnits +{ + MetersPerSecond, + CentimetersPerSecond +} + +public struct Speed +{ + public decimal Amount { get; } + public SpeedUnits SpeedUnits { get; } + + public Speed(decimal amount, SpeedUnits speedUnits) + { + Amount = amount; + SpeedUnits = speedUnits; + } + + public override string ToString() + { + string unitsString = "meters per second"; + if (SpeedUnits == SpeedUnits.CentimetersPerSecond) + { + unitsString = "centimeters per second"; + } + + return Amount + " " + unitsString; + } +} diff --git a/exercises/concept/nested-types/NestedTypes.csproj b/exercises/concept/nested-types/NestedTypes.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/nested-types/NestedTypes.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/nested-types/NestedTypesTests.cs b/exercises/concept/nested-types/NestedTypesTests.cs new file mode 100644 index 0000000000..43c7be8264 --- /dev/null +++ b/exercises/concept/nested-types/NestedTypesTests.cs @@ -0,0 +1,23 @@ +using Xunit; + +public class NestedTypeTests +{ + [Fact] + public void ShowSponsor() + { + var car = new RemoteControlCar(); + string expected = "Walker Industries Inc."; + car.Telemetry.ShowSponsor(expected); + Assert.Equal(expected, car.CurrentSponsor); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ShowSpeed() + { + var car = new RemoteControlCar(); + string expected = "100 meters per second"; + decimal expectedAmount = 100; + car.Telemetry.SetSpeed(100, "mps"); + Assert.Equal(expected, car.GetSpeed()); + } +} From f0e6f6c5e98ec0405dd57877b94e9c990b57528a Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 14 Jul 2020 10:47:57 -0400 Subject: [PATCH 177/327] structs - added contributors * Update config.json * Update config.json --- exercises/concept/structs/.meta/config.json | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/exercises/concept/structs/.meta/config.json b/exercises/concept/structs/.meta/config.json index 315b869235..e209e130a3 100644 --- a/exercises/concept/structs/.meta/config.json +++ b/exercises/concept/structs/.meta/config.json @@ -1,4 +1,14 @@ { + "contributors": [ + { + "github_username": "efx", + "exercism_username": "efx" + }, + { + "github_username": "jrr", + "exercism_username": "jrr" + } + ], "authors": [ { "github_username": "mikedamay", From 80be01b19b8b56cf0e6f67fe7fbb674ba37f032a Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 15 Jul 2020 02:55:14 -0400 Subject: [PATCH 178/327] misspelling of "prerequisiites" in multiple files * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * prequisites misspelling s/be prerequisites Co-authored-by: Erik Schierboom --- exercises/concept/arrays/.meta/design.md | 2 +- exercises/concept/basics/.meta/design.md | 2 +- exercises/concept/booleans/.meta/design.md | 2 +- exercises/concept/chars/.meta/design.md | 2 +- exercises/concept/classes/.meta/design.md | 2 +- exercises/concept/constructors/.meta/design.md | 2 +- exercises/concept/datetimes/.meta/design.md | 2 +- exercises/concept/dictionaries/.meta/design.md | 2 +- exercises/concept/enums/.meta/design.md | 2 +- exercises/concept/equality/.meta/design.md | 2 +- exercises/concept/flag-enums/.meta/design.md | 2 +- exercises/concept/floating-point-numbers/.meta/design.md | 2 +- exercises/concept/inheritance/.meta/design.md | 2 +- exercises/concept/method-overloading/.meta/design.md | 2 +- exercises/concept/numbers/.meta/design.md | 2 +- exercises/concept/overflow/.meta/design.md | 2 +- exercises/concept/parameters/.meta/design.md | 2 +- exercises/concept/properties/.meta/design.md | 2 +- exercises/concept/strings/.meta/design.md | 2 +- exercises/concept/structs/.meta/design.md | 2 +- exercises/concept/tuples/.meta/design.md | 2 +- exercises/concept/user-defined-exceptions/.meta/design.md | 2 +- 22 files changed, 22 insertions(+), 22 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 414b7a8106..34ec77d170 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -28,7 +28,7 @@ Of the many available C# collection types, we chose to use the `array` collectio - `for-loops`: know how to use a `for` loop to do iteration. - `foreach-loops`: know how to iterate over a collection. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index c25b0ffcc1..1e1bbd478f 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -32,7 +32,7 @@ - `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. -## Prequisites +## Prerequisites There are no prerequisites. diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/booleans/.meta/design.md index f2401cd437..88fc902ed4 100644 --- a/exercises/concept/booleans/.meta/design.md +++ b/exercises/concept/booleans/.meta/design.md @@ -12,7 +12,7 @@ - `booleans`: know of the existence of the `bool` type and its two values; know about boolean operators and how to build logical expressions with them; know of the boolean operator precedence rules. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/chars/.meta/design.md b/exercises/concept/chars/.meta/design.md index 77e020d13f..e129ece710 100644 --- a/exercises/concept/chars/.meta/design.md +++ b/exercises/concept/chars/.meta/design.md @@ -22,7 +22,7 @@ - `chars`: know of the existence of the `char` type; know that a `char` represents; know how to define a `char`; know how to access a `char` in a string by index; know of some basic `char` methods (like converting to uppercase). - `StringBuilder`: know how to use this. -## Prequisites +## Prerequisites - `strings`: know of the `string` type that will be iterated over and accessed by index. - `for-loop` for loops (rather than foreach) are the best means of highlighting the relationship between strings and `char`s diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index df42404c6b..db1b67b9d6 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -25,7 +25,7 @@ - `classes`: know what classes are; know what encapsulation is; know what fields are; know how to create an object; know how to update state through methods; know about the `void` type. -## Prequisites +## Prerequisites - `basics`: know how to define a basic class with basic methods. - `strings`: know how to do basic string interpolation. diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md index 2e63932043..5a9f755ddf 100644 --- a/exercises/concept/constructors/.meta/design.md +++ b/exercises/concept/constructors/.meta/design.md @@ -15,7 +15,7 @@ - `constructors`: know what constructors are; know how to define parameterless constructors; know how to define parameterized constructors; know how to use constructor overloading; know how to define private constructors. -## Prequisites +## Prerequisites - `classes`: know how to work with classes. - `numbers`: know how compare numbers. diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/datetimes/.meta/design.md index eee4a91147..ef0b32d677 100644 --- a/exercises/concept/datetimes/.meta/design.md +++ b/exercises/concept/datetimes/.meta/design.md @@ -20,7 +20,7 @@ - `datetime`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa; know of the existence of the `DateTime` type; know of the individual, time-related properties. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md index b3157c7ccf..8910f3ef31 100644 --- a/exercises/concept/dictionaries/.meta/design.md +++ b/exercises/concept/dictionaries/.meta/design.md @@ -22,7 +22,7 @@ - `dictionaries`: know of the existence of the `Dictionary` type; know how to define a dictionary; know how to add and updated elements in a dictionary; know how to access elements in a dictionary by key; know how to iterate over elements in a dictionary; know some basic dictionary functions. -## Prequisites +## Prerequisites - `foreach-loops`: know how to use a `foreach-loop` to iterate over a collection. - `generic-types`: know how generic types work. diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index a48667033d..807e413789 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -20,7 +20,7 @@ After completing this exercise, the student should: - `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert an `enum` to a `string`. - `pattern-matching-constants`: know how to use the `switch` statement to do constant pattern matching. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/equality/.meta/design.md index 292c325dce..93cf87be5b 100644 --- a/exercises/concept/equality/.meta/design.md +++ b/exercises/concept/equality/.meta/design.md @@ -19,7 +19,7 @@ This Concepts Exercise's Concepts are: - `equality`: know how to check for equality and inequality; know how reference equality differs from structural equality; know that equality works by default for value and reference types; know how to customize equality checks using `Equals` and `GetHashCode()`; know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them. - `sets`: Know how to use hash sets `HashSet` as provided by the .NET BCL. Understand the relationship with `Object.GetHashCode()` and the performance charateristics of hash sets. -## Prequisites +## Prerequisites This Concept Exercise's prerequisites Concepts are: diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md index 8e7b627327..c08fa24824 100644 --- a/exercises/concept/flag-enums/.meta/design.md +++ b/exercises/concept/flag-enums/.meta/design.md @@ -17,7 +17,7 @@ As this is an advanced exercise, there are no enum-related things that we should - `flag-enums`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. - `bit-manipulation`: know how to use bitwise operators to manipulate bits. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index 71b098ce12..780f2cdd0c 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -15,7 +15,7 @@ - `floating-point-numbers`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. - `while-loops`: know how to write a `while` loop. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index 0f479185fd..e965967e05 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -16,7 +16,7 @@ - `inheritance`: know what inheritance is; know how to inherit from a class; know that all types inherit from `object`; know what abstract and sealed classes are; know what abstract and virtual methods are; know how to override methods; know about the `protected` visibility modifier. -## Prequisites +## Prerequisites - `classes`: know how to work with classes. - `constructors`: know how to work with constructors. diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/method-overloading/.meta/design.md index 8387dea33f..233480bcb3 100644 --- a/exercises/concept/method-overloading/.meta/design.md +++ b/exercises/concept/method-overloading/.meta/design.md @@ -16,7 +16,7 @@ - `optional-parameters`: know how to define optional parameters - `named-arguments`: know how to use named arguments -## Prequisites +## Prerequisites - `classes`: know how to define methods on classes - `constructors`: know how to define constructors on classes diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index fa0e0262fc..b0efa68995 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -17,7 +17,7 @@ - `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to convert from one numeric type to another; know what implicit and explicit conversions are. - `conditionals`: know how to conditionally execute code using an `if` statement. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/overflow/.meta/design.md b/exercises/concept/overflow/.meta/design.md index eb815702e9..695df09856 100644 --- a/exercises/concept/overflow/.meta/design.md +++ b/exercises/concept/overflow/.meta/design.md @@ -12,7 +12,7 @@ - `overflows`: explain integral number overflows; explain floating-point number overflows; know how to use `checked` and `unchecked` to deal with overflows. -## Prequisites +## Prerequisites - `integral-numbers`: know about the integral number types. - `floating-point-numbers`: know about the floating-point number types. diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/parameters/.meta/design.md index edd56ea42f..8edaf9fbf2 100644 --- a/exercises/concept/parameters/.meta/design.md +++ b/exercises/concept/parameters/.meta/design.md @@ -16,7 +16,7 @@ This Concepts Exercise's Concepts are: - `parameters`: know the difference between value and reference type parameters; know how to pass value types by reference using the `ref` and `out` modifiers. -## Prequisites +## Prerequisites This Concept Exercise's prerequisites Concepts are: diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index 093d1f6c88..5e6e59b784 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -24,7 +24,7 @@ Note that students may choose to implement expression-bodied members. - `properties`: know what properties are and how they relate to fields and methods; know what backing-field properties are; know what auto-implemented properties are; know what calculated properties are; know how to use property accessors to customize visibility; know how to define the different types of properties. -## Prequisites +## Prerequisites - `numbers`: using the `int` type and using mathematical operators and number conversions. - `floating-point-numbers`: using the `decimal` type. diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/strings/.meta/design.md index 8aba8b9d78..fe18990027 100644 --- a/exercises/concept/strings/.meta/design.md +++ b/exercises/concept/strings/.meta/design.md @@ -15,7 +15,7 @@ - `strings`: know of the existence of the `string` type; know of some basic functions (like looking up a character at a position, or slicing the string); know how to do basic string formatting. -## Prequisites +## Prerequisites This exercise's prerequisites Concepts are: diff --git a/exercises/concept/structs/.meta/design.md b/exercises/concept/structs/.meta/design.md index 436b788e6d..1824ed74db 100644 --- a/exercises/concept/structs/.meta/design.md +++ b/exercises/concept/structs/.meta/design.md @@ -21,7 +21,7 @@ This Concepts Exercise's Concepts are: - `structs`: know what structs are; know how to define a `struct`; know how to add members to structs; know the differences between structs and classes. -## Prequisites +## Prerequisites - `inheritance`: know that all types are derived from `object`. - `classes`: know how to define and work with classes. diff --git a/exercises/concept/tuples/.meta/design.md b/exercises/concept/tuples/.meta/design.md index b077232e57..2f05df06fb 100644 --- a/exercises/concept/tuples/.meta/design.md +++ b/exercises/concept/tuples/.meta/design.md @@ -17,7 +17,7 @@ - `tuples`: know what a tuple is; know how to define a tuple; know how to name tuple fields; know that tuples have structural equality; know how to deconstruct tuples; know that tuples are mutable. -## Prequisites +## Prerequisites - `basics`: know how to define methods and variables. - `strings`: obtaining sub-strings from a string diff --git a/exercises/concept/user-defined-exceptions/.meta/design.md b/exercises/concept/user-defined-exceptions/.meta/design.md index 374a5e39cc..5812eb8e5f 100644 --- a/exercises/concept/user-defined-exceptions/.meta/design.md +++ b/exercises/concept/user-defined-exceptions/.meta/design.md @@ -15,7 +15,7 @@ This Concepts Exercise's Concepts are: - `user-defined-exceptions`: know how to define a user-defined exception. - `exception-filtering`: know how to use exception filtering. -## Prequisites +## Prerequisites This Concept Exercise's prerequisites Concepts are: From 16d80d87ab09e756594611eb3683575255c23915 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 15 Jul 2020 11:17:38 +0200 Subject: [PATCH 179/327] Add new object mention in basics introduction Add new object mention in basics introduction --- exercises/concept/basics/.docs/after.md | 31 +++++++++++++------ .../concept/basics/.docs/introduction.md | 18 +++++------ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md index 65ad0e9fb0..343febaddd 100644 --- a/exercises/concept/basics/.docs/after.md +++ b/exercises/concept/basics/.docs/after.md @@ -15,33 +15,42 @@ count = 2; // Update to new value // count = false; ``` -C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from functions using the [`return` keyword][return]. To allow a method to be called by code in other files, the `public` access modifier must be added. +C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. Objects (or _instances_) are created by using the `new` keyword. ```csharp class Calculator { - public int Add(int x, int y) - { - return x + y; - } + // ... } + +var calculator = new Calculator(); ``` -Invoking a method is done by specifying its class- and method name and passing arguments for each of the method's parameters. +A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from methods using the [`return` keyword][return]. To allow a method to be called by code in other files, the `public` access modifier must be added. ```csharp -var sum = Calculator.Add(1, 2); +class Calculator +{ + public int Add(int x, int y) + { + return x + y; + } +} ``` -Arguments can optionally specify the corresponding parameter's name: +Methods are invoked using dot (`.`) syntax on an instance, specifying the method name to call and passing arguments for each of the method's parameters. Arguments can optionally specify the corresponding parameter's name. ```csharp -var sum = Calculator.Add(x: 1, y: 2); +var calculator = new Calculator(); +var sum_v1 = calculator.Add(1, 2); +var sum_v2 = calculator.Add(x: 1, y: 2); ``` If the method to be called is defined in the same class as the method that calls it, the class name can be omitted. -If a method does not use any class _state_ (which is the case in this exercise), the method can be made _static_ using the `static` modifier. Similarly, if a class only has static methods, it too can be made static using the `static` modifier. +If a method does not use any object _state_, the method can be made _static_ using the `static` modifier. Static methods are also invoked using dot (`.`) syntax, but are invoked on the class itself instead of an instance of the class. + +If a class only has static methods, it too can be made static using the `static` modifier. This expresses the intention of the class. ```csharp static class Calculator @@ -51,6 +60,8 @@ static class Calculator return x * y; } } + +Calculator.Multiply(2, 4); // => 8 ``` Scope in C# is defined between the `{` and `}` characters. diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/basics/.docs/introduction.md index 7239f44996..a0da40de82 100644 --- a/exercises/concept/basics/.docs/introduction.md +++ b/exercises/concept/basics/.docs/introduction.md @@ -15,16 +15,18 @@ count = 2; // Update to new value // count = false; ``` -C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. +C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. Objects (or _instances_) are created by using the `new` keyword. ```csharp class Calculator { // ... } + +var calculator = new Calculator(); ``` -A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from functions using the `return` keyword. To allow a method to be called by code in other files, the `public` access modifier must be added. +A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from methods using the `return` keyword. To allow a method to be called by code in other files, the `public` access modifier must be added. ```csharp class Calculator @@ -36,16 +38,12 @@ class Calculator } ``` -Invoking a method is done by specifying its class- and method name and passing arguments for each of the method's parameters. - -```csharp -var sum = Calculator.Add(1, 2); -``` - -Arguments can optionally specify the corresponding parameter's name: +Methods are invoked using dot (`.`) syntax on an instance, specifying the method name to call and passing arguments for each of the method's parameters. Arguments can optionally specify the corresponding parameter's name. ```csharp -var sum = Calculator.Add(x: 1, y: 2); +var calculator = new Calculator(); +var sum_v1 = calculator.Add(1, 2); +var sum_v2 = calculator.Add(x: 1, y: 2); ``` Scope in C# is defined between the `{` and `}` characters. From 456526d9a7574760da25f1ec2eb3650900e255d2 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 16 Jul 2020 03:46:56 -0400 Subject: [PATCH 180/327] various - added contributors * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * lists initial commit * lists code complete * lists added instructions * Update languages/exercises/concept/lists/.meta/Example.cs Co-authored-by: Erik Schierboom * lists review points * Update languages/exercises/concept/lists/.docs/instructions.md Co-authored-by: Erik Schierboom * lists finalizing * lists finalizing * lists finalized code * lists proofing * lists proofed added contributors * deleted unwanted files Co-authored-by: Erik Schierboom --- exercises/concept/casting/.meta/config.json | 6 ++++++ exercises/concept/chars/.meta/config.json | 6 ++++++ exercises/concept/dictionaries/.meta/config.json | 6 ++++++ exercises/concept/equality/.meta/config.json | 6 ++++++ exercises/concept/nested-types/.meta/config.json | 6 ++++++ exercises/concept/object-initializers/.meta/config.json | 6 ++++++ exercises/concept/overflow/.meta/config.json | 4 ++++ exercises/concept/parameters/.meta/config.json | 6 ++++++ exercises/concept/properties/.meta/config.json | 6 ++++++ exercises/concept/randomness/.meta/config.json | 6 ++++++ exercises/concept/regular-expressions/.meta/config.json | 6 ++++++ exercises/concept/resource-cleanup/.meta/config.json | 6 ++++++ exercises/concept/resource-lifetime/.meta/config.json | 6 ++++++ exercises/concept/structs/.meta/config.json | 4 ++++ exercises/concept/switch-statements/.meta/config.json | 6 ++++++ exercises/concept/time/.meta/config.json | 6 ++++++ exercises/concept/tuples/.meta/config.json | 6 ++++++ exercises/concept/user-defined-exceptions/.meta/config.json | 6 ++++++ 18 files changed, 104 insertions(+) diff --git a/exercises/concept/casting/.meta/config.json b/exercises/concept/casting/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/casting/.meta/config.json +++ b/exercises/concept/casting/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/chars/.meta/config.json b/exercises/concept/chars/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/chars/.meta/config.json +++ b/exercises/concept/chars/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/dictionaries/.meta/config.json b/exercises/concept/dictionaries/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/dictionaries/.meta/config.json +++ b/exercises/concept/dictionaries/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/equality/.meta/config.json b/exercises/concept/equality/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/equality/.meta/config.json +++ b/exercises/concept/equality/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/nested-types/.meta/config.json b/exercises/concept/nested-types/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/nested-types/.meta/config.json +++ b/exercises/concept/nested-types/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/object-initializers/.meta/config.json b/exercises/concept/object-initializers/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/object-initializers/.meta/config.json +++ b/exercises/concept/object-initializers/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/overflow/.meta/config.json b/exercises/concept/overflow/.meta/config.json index be058a23f7..0816f0d60a 100644 --- a/exercises/concept/overflow/.meta/config.json +++ b/exercises/concept/overflow/.meta/config.json @@ -11,6 +11,10 @@ { "github_username": "saschamann", "exercism_username": "saschamann" + }, + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" } ], "authors": [ diff --git a/exercises/concept/parameters/.meta/config.json b/exercises/concept/parameters/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/parameters/.meta/config.json +++ b/exercises/concept/parameters/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/properties/.meta/config.json +++ b/exercises/concept/properties/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/randomness/.meta/config.json b/exercises/concept/randomness/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/randomness/.meta/config.json +++ b/exercises/concept/randomness/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/regular-expressions/.meta/config.json b/exercises/concept/regular-expressions/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/regular-expressions/.meta/config.json +++ b/exercises/concept/regular-expressions/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/resource-cleanup/.meta/config.json b/exercises/concept/resource-cleanup/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/resource-cleanup/.meta/config.json +++ b/exercises/concept/resource-cleanup/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/resource-lifetime/.meta/config.json b/exercises/concept/resource-lifetime/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/resource-lifetime/.meta/config.json +++ b/exercises/concept/resource-lifetime/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/structs/.meta/config.json b/exercises/concept/structs/.meta/config.json index e209e130a3..01d444e131 100644 --- a/exercises/concept/structs/.meta/config.json +++ b/exercises/concept/structs/.meta/config.json @@ -7,6 +7,10 @@ { "github_username": "jrr", "exercism_username": "jrr" + }, + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" } ], "authors": [ diff --git a/exercises/concept/switch-statements/.meta/config.json b/exercises/concept/switch-statements/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/switch-statements/.meta/config.json +++ b/exercises/concept/switch-statements/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/time/.meta/config.json b/exercises/concept/time/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/time/.meta/config.json +++ b/exercises/concept/time/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/tuples/.meta/config.json b/exercises/concept/tuples/.meta/config.json index 315b869235..9212d455d1 100644 --- a/exercises/concept/tuples/.meta/config.json +++ b/exercises/concept/tuples/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", diff --git a/exercises/concept/user-defined-exceptions/.meta/config.json b/exercises/concept/user-defined-exceptions/.meta/config.json index 3865ea9589..8b317279aa 100644 --- a/exercises/concept/user-defined-exceptions/.meta/config.json +++ b/exercises/concept/user-defined-exceptions/.meta/config.json @@ -1,4 +1,10 @@ { + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], "authors": [ { "github_username": "mikedamay", From 413e8fa7fefd6cad625ae587e9c9d75f301b08a5 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 16 Jul 2020 04:23:54 -0400 Subject: [PATCH 181/327] lists new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * lists initial commit * lists code complete * lists added instructions * Update languages/exercises/concept/lists/.meta/Example.cs Co-authored-by: Erik Schierboom * lists review points * Update languages/exercises/concept/lists/.docs/instructions.md Co-authored-by: Erik Schierboom * lists finalizing * lists finalizing * lists finalized code * lists proofing * lists proofed * Apply suggestions from code review Co-authored-by: Erik Schierboom * lists review points * lists added config.json * lists prettier * lists added contributors Co-authored-by: Erik Schierboom --- exercises/concept/lists/.docs/after.md | 38 ++++++ exercises/concept/lists/.docs/hints.md | 46 +++++++ exercises/concept/lists/.docs/instructions.md | 101 ++++++++++++++ exercises/concept/lists/.docs/introduction.md | 9 ++ exercises/concept/lists/.meta/Example.cs | 76 +++++++++++ exercises/concept/lists/.meta/config.json | 15 ++ exercises/concept/lists/.meta/design.md | 31 +++++ exercises/concept/lists/Lists.cs | 50 +++++++ exercises/concept/lists/Lists.csproj | 13 ++ exercises/concept/lists/ListsTests.cs | 129 ++++++++++++++++++ 10 files changed, 508 insertions(+) create mode 100644 exercises/concept/lists/.docs/after.md create mode 100644 exercises/concept/lists/.docs/hints.md create mode 100644 exercises/concept/lists/.docs/instructions.md create mode 100644 exercises/concept/lists/.docs/introduction.md create mode 100644 exercises/concept/lists/.meta/Example.cs create mode 100644 exercises/concept/lists/.meta/config.json create mode 100644 exercises/concept/lists/.meta/design.md create mode 100644 exercises/concept/lists/Lists.cs create mode 100644 exercises/concept/lists/Lists.csproj create mode 100644 exercises/concept/lists/ListsTests.cs diff --git a/exercises/concept/lists/.docs/after.md b/exercises/concept/lists/.docs/after.md new file mode 100644 index 0000000000..344684188b --- /dev/null +++ b/exercises/concept/lists/.docs/after.md @@ -0,0 +1,38 @@ +Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as [`List`][lists-docs] where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. + +```csharp +var listOfStrings = new List(); +var listOfIntegers = new List(); +var listOfRandoms = new List(); +var listOfBigIntegers = new List(); +``` + +A collection definition typically includes a place holder in angle brackets, often `T` by convention. This allows the collection user to specify what type of items to store in the collection. + +Unlike arrays (TODO cross-ref-tba) lists can resize themselves dynamically. + +#### Generic classes + +Lists are an example of generic classes. You will also see `HashSet` and `Dictionary` in early exercises. + +More [advanced generic techniques][generics] are discussed in (TODO cross-ref-tba) including creating your own generics. + +If you need a list of different types then you can use `List` but you will need to [down cast][casting] elements that you access in from the list. + +You should also be aware of `System.Collections.List` which you may encounter in legacy code. To all intents and purposes this behaves like `List`. + +#### LINQ + +Although the built-in API of `List` is rich (including mappings and filters such as `ConvertAll`, `FindAll` and `Foreach`) and its [looping syntax][for-each] is very clear, and you definitely need to be familiar with this API, Language Integrated Query ([LINQ][linq]) is available for many tasks, is even more powerful and widely used and has the advantage of providing a consistent interface across library collections, third-party collections and your own classes. See (TODO cross-ref-tba). + +#### Reference + +- [List documentation][lists-docs]: reference documentation for `List`. +- [Lists tutorial][lists-tutorial]: basic tutorial on how to work with lists. + +[lists-docs]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1 +[lists-tutorial]: https://csharp.net-tutorials.com/collections/lists/ +[generics]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/ +[casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions +[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ +[for-each]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in diff --git a/exercises/concept/lists/.docs/hints.md b/exercises/concept/lists/.docs/hints.md new file mode 100644 index 0000000000..242830716e --- /dev/null +++ b/exercises/concept/lists/.docs/hints.md @@ -0,0 +1,46 @@ +## General + +- [List documentation][lists-docs]: reference documentation for `List`. +- [Lists tutorial][lists-tutorial]: basic tutorial on how to work with lists. + +## 1. Create a new list + +- Generic collections are instantiated like any others with the `new` operator. Remember to substitute any reference to the generic parameter, `T` with the type of the items in your collection. + +## 2. Define an existing list + +- See this [article][list-add] on adding an item. + +## 4. Count the languages in the list + +- See this [article][list-count] on retrieving the number of items in a list. + +## 5. Check to see if a language is in the list + +- See this [article][list-contains] on checking if an item is in a list. + +## 6. Reverse the list + +- See this [article][list-reverse] on reversing a list. + +## 7. Check if list is exciting + +- See this [article][list-item] on retrieving an item by its index within the list. + +## 8.Remove Language + +- See this [article][list-remove] on removing an item from the list. + +## 9. Check if all languages in the list are unique + +- See this [article][list-sort] on sorting and [this][list-item] on retrieving an item by its index. + +[lists-docs]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1 +[lists-tutorial]: https://csharp.net-tutorials.com/collections/lists/ +[list-add]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.add?view=netcore-3.1 +[list-count]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.count?view=netcore-3.1 +[list-contains]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.contains?view=netcore-3.1 +[list-reverse]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.reverse?view=netcore-3.1 +[list-item]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.item?view=netcore-3.1 +[list-remove]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.remove?view=netcore-3.1 +[list-sort]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=netcore-3.1 diff --git a/exercises/concept/lists/.docs/instructions.md b/exercises/concept/lists/.docs/instructions.md new file mode 100644 index 0000000000..769a6f4f14 --- /dev/null +++ b/exercises/concept/lists/.docs/instructions.md @@ -0,0 +1,101 @@ +In this exercise you'll be writing code to keep track of a list of programming languages you want to learn on Exercism. + +You have nine tasks, which will all involve dealing with lists. + +## 1. Create a new list + +To keep track of the languages you want to learn, you'll need to create a new list. + +Implement the static `Languages.NewList()` method that returns a new, empty list. + +```fsharp +Languages.NewList() +// => empty list +``` + +## 2. Define an existing list + +Currently, you have a piece of paper listing the languages you want to learn: C#, Clojure and Elm. + +Please implement the static `Languages.GetExistingLanguages()` method to return the list. + +```fsharp +Languages.GetExistingLanguages(); +// => {"C#", "Clojure", "Elm"} +``` + +## 3. Add a new language to a list + +As you explore Exercism and find more interesting languages, you want to add them to your list. + +Implement the static `Languages.AddLanguage()` function to add a new language to the end of your list. + +```fsharp +Languages.AddLanguage(Languages.GetExistingLanguages(), "VBA"); +// => {"C#", "Clojure", "Elm", "VBA"} +``` + +## 4. Count the languages in the list + +Counting the languages one-by-one is inconvenient. + +Implement the static `Languages.CountLanguages()` method to count the number of languages on your list. + +```fsharp +Languages.CountLanguages(Languages.GetExistingLanguages()) +// => 3 +``` + +## 5. Check to see if a language is in the list + +Implement the static `Languages.HasLanguage()` method to check if a language is present. + +```csharp +Languages.HasLanguage(Languages.GetExistingLanguages(), "Elm") +// => true +``` + +## 6. Reverse the list + +At some point, you realize that your list is actually ordered backwards! + +Implement the static `Languages.ReverseList()` method to reverse your list. + +```fsharp +Languages.ReverseList(Languages.GetExistingLanguages()) +// => {"Elm", "Clojure", "C#"} +``` + +## 7. Check if list is exciting + +While you love all languages, C# has a special place in your heart. As such, you're really excited about a list of languages if: + +- The first on the list is C#. +- The second item on the list is C# and the list contain either two or three languages. + +Implement the static `Languages.ContainsStar()` method to check if a list of languages is exciting: + +```fsharp +Languages.ContainsStar(Languages.GetExistingLanguages()) +// => true +``` + +## 8.Remove Language + +Please implement the static `Languages.RemoveLangage()` method to remove a specified language from the list. + +```csharp +Languages.RemoveLanguage(Languages.GetExistingLanguages(), "Clojure") +// => { "C#", "Elm" } +``` + +## 9. Check if all languages in the list are unique + +Please implement the static `Languages.EnsureUnique()` method to check if any of the languages is repeated in the list. + +The list of languages (i.e. the parameter) is guaranteed not to be empty when this method is called and it doesn't matter if the list is modified. + +```csharp +Languages.EnsureUnique(Languages.GetExistingLanguages()) +// => true +``` diff --git a/exercises/concept/lists/.docs/introduction.md b/exercises/concept/lists/.docs/introduction.md new file mode 100644 index 0000000000..ccdfef907b --- /dev/null +++ b/exercises/concept/lists/.docs/introduction.md @@ -0,0 +1,9 @@ +Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. `List` is generally referred to as a generic type and that `T` is the type parameter. + +Items can be added to and removed from lists. They grow and shrink as necessary. + +```csharp +var listOfStrings = new List(); +``` + +A collection definition typically includes a place holder in angle brackets, often `T` by convention. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings. diff --git a/exercises/concept/lists/.meta/Example.cs b/exercises/concept/lists/.meta/Example.cs new file mode 100644 index 0000000000..c87fca38b5 --- /dev/null +++ b/exercises/concept/lists/.meta/Example.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; + +public static class Languages +{ + public static List NewList() + { + return new List(); + } + + public static List GetExistingLanguages() + { + var languages = new List(); + languages.Add("C#"); + languages.Add("Clojure"); + languages.Add("Elm"); + return languages; + } + + public static List AddLanguage(List languages, string language) + { + languages.Add(language); + return languages; + } + + public static int CountLanguages(List languages) + { + return languages.Count; + } + + public static bool HasLanguage(List languages, string language) + { + return languages.Contains(language); + } + + public static List ReverseList(List languages) + { + languages.Reverse(); + return languages; + } + + public static bool ContainsStar(List languages) + { + if (languages.Count > 0 && languages[0] == "C#") + { + return true; + } + + if (languages.Count > 1 && languages.Count < 4 && languages[1] == "C#") + { + return true; + } + + return false; + } + + public static List RemoveLanguage(List languages, string language) + { + languages.Remove(language); + return languages; + } + + // guaranteed not empty + public static bool EnsureUnique(List languages) + { + languages.Sort(); + for (int i = 1; i < languages.Count; i++) + { + if (languages[i] == languages[i - 1]) + { + return false; + } + } + + return true; + } +} diff --git a/exercises/concept/lists/.meta/config.json b/exercises/concept/lists/.meta/config.json new file mode 100644 index 0000000000..87e49b7fcb --- /dev/null +++ b/exercises/concept/lists/.meta/config.json @@ -0,0 +1,15 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "forked_from": ["fsharp/lists"] +} diff --git a/exercises/concept/lists/.meta/design.md b/exercises/concept/lists/.meta/design.md new file mode 100644 index 0000000000..8880eec65e --- /dev/null +++ b/exercises/concept/lists/.meta/design.md @@ -0,0 +1,31 @@ +## Learning objectives + +- Know what generic types are. +- Know of the existence of the `List` type. +- Know how a list is different from an array. +- Know how to define a list. +- Know how to add and remove elements from a list. +- Know how to access elements in a list by their index. +- Know how to iterate over elements in a list. +- Know some basic list functions (like finding the index of an element in a list or sorting a list). + +## Out of scope + +- Generic functions. +- Generic constraints. +- Memory and performance characteristics. +- LINQ. +- Concurrency issues. +- Co-/contravariance. +- Equality. +- List resizing due to it using an array as its data type. + +## Concepts + +- `lists`: know of the existence of the `List` type; know how a list is different from an array; know how to define a list; know how to add and remove elements from a list; know how to access elements in a list by their index; know how to iterate over elements in a list; know some basic list functions (like finding the index of an element in a list). +- `generic-types`: know what generic types are. + +## Prerequisites + +- `for-loops`: know how to use a `for-loop` to iterate over a collection. +- `arrays`: contrast with dynamic nature of lists diff --git a/exercises/concept/lists/Lists.cs b/exercises/concept/lists/Lists.cs new file mode 100644 index 0000000000..f66081c783 --- /dev/null +++ b/exercises/concept/lists/Lists.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; + +public static class Languages +{ + public static List NewList() + { + throw new NotImplementedException("Please implement the static Languages.NewList() method"); + } + + public static List GetExistingLanguages() + { + throw new NotImplementedException("Please implement the static Languages.GetExistingLanguages() method"); + } + + public static List AddLanguage(List languages, string language) + { + throw new NotImplementedException("Please implement the static Languages.AddLanguage() method"); + } + + public static int CountLanguages(List languages) + { + throw new NotImplementedException("Please implement the static Languages.CountLanguages() method"); + } + + public static bool HasLanguage(List languages, string language) + { + throw new NotImplementedException("Please implement the static Languages.HasLanguage() method"); + } + + public static List ReverseList(List languages) + { + throw new NotImplementedException("Please implement the static Languages.ReverseList() method"); + } + + public static bool ContainsStar(List languages) + { + throw new NotImplementedException("Please implement the static Languages.ContainsStar() method"); + } + + public static List RemoveLanguage(List languages, string language) + { + throw new NotImplementedException("Please implement the static Languages.RemoveLanguage() method"); + } + + public static bool EnsureUnique(List languages) + { + throw new NotImplementedException("Please implement the static Languages.EnsureUnique() method"); + } +} diff --git a/exercises/concept/lists/Lists.csproj b/exercises/concept/lists/Lists.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/lists/Lists.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/lists/ListsTests.cs b/exercises/concept/lists/ListsTests.cs new file mode 100644 index 0000000000..b2bee11a38 --- /dev/null +++ b/exercises/concept/lists/ListsTests.cs @@ -0,0 +1,129 @@ +using System.Collections.Generic; +using Xunit; + +public class ListsTests +{ + [Fact] + public void NewList() + { + Assert.Empty(Languages.NewList()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ExistingList() + { + var expected = new List(); + expected.Add("C#"); + expected.Add("Clojure"); + expected.Add("Elm"); + Assert.Equal(expected, Languages.GetExistingLanguages()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AddLanguage() + { + var expected = new List(); + expected.Add("C#"); + expected.Add("Clojure"); + expected.Add("Elm"); + expected.Add("Bash"); + Assert.Equal(expected, + Languages.AddLanguage(Languages.GetExistingLanguages(), "Bash")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void CountLanguages() + { + Assert.Equal(3, + Languages.CountLanguages(Languages.GetExistingLanguages())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void HasLanguage_yes() + { + Assert.True(Languages.HasLanguage(Languages.GetExistingLanguages(), "Elm")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void HasLanguage_no() + { + Assert.False(Languages.HasLanguage(Languages.GetExistingLanguages(), "D")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ReverseList() + { + var expected = new List(); + expected.Add("Elm"); + expected.Add("Clojure"); + expected.Add("C#"); + Assert.Equal(expected, + Languages.ReverseList(Languages.GetExistingLanguages())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ContainsStar_yes() + { + Assert.True(Languages.ContainsStar(Languages.GetExistingLanguages())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ContainsStar_too_many() + { + var languages = Languages.GetExistingLanguages(); + languages.Insert(0, "VBA"); + Assert.False(Languages.ContainsStar(languages)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ContainsStar_empty() + { + var languages = Languages.NewList(); + Assert.False(Languages.ContainsStar(languages)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ContainsStar_single_star() + { + var languages = Languages.GetExistingLanguages(); + languages.RemoveAt(2); + languages.RemoveAt(1); + Assert.True(Languages.ContainsStar(languages)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void RemoveLanguage_yes() + { + var expected = new List(); + expected.Add("C#"); + expected.Add("Elm"); + var languages = Languages.GetExistingLanguages(); + Assert.Equal(expected, Languages.RemoveLanguage(languages, "Clojure")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void RemoveLanguage_no() + { + var expected = new List(); + expected.Add("C#"); + expected.Add("Clojure"); + expected.Add("Elm"); + var languages = Languages.GetExistingLanguages(); + Assert.Equal(expected, Languages.RemoveLanguage(languages, "English")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void EnsureUnique_yes() + { + var languages = Languages.GetExistingLanguages(); + Assert.True(Languages.EnsureUnique(languages)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void EnsureUnique_no() + { + var languages = Languages.GetExistingLanguages(); + languages.Add("C#"); + Assert.False(Languages.EnsureUnique(languages)); + } +} From 26078d33b2c90ffb39a3cb6f29618f3ecc969fe1 Mon Sep 17 00:00:00 2001 From: Mike May Date: Mon, 20 Jul 2020 23:42:40 -0400 Subject: [PATCH 182/327] string-formatting new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * string-formatting added from old branch after repo snafu * string-formatting code improvement * string-formatting before dropping description of custom formatting and `ICustomFormatter` * string-formatting after dropping description of custom formatting and `ICustomFormatter` * string-formatting removed links * string-formatting links * string-formatting tweaks * string-formatting tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * nested-types forward to final PR * string-formatting - various clarifications * string-formatting - typos * string-formatting typo * Apply suggestions from code review Co-authored-by: Erik Schierboom * string-formatting config.json+ Co-authored-by: Erik Schierboom --- .../concept/string-formatting/.docs/after.md | 131 ++++++++++++++++++ .../concept/string-formatting/.docs/hints.md | 37 +++++ .../string-formatting/.docs/instructions.md | 47 +++++++ .../string-formatting/.docs/introduction.md | 68 +++++++++ .../string-formatting/.meta/Example.cs | 43 ++++++ .../string-formatting/.meta/config.json | 15 ++ .../concept/string-formatting/.meta/design.md | 26 ++++ .../string-formatting/StringFormatting.cs | 20 +++ .../string-formatting/StringFormatting.csproj | 13 ++ .../StringFormattingTests.cs | 45 ++++++ 10 files changed, 445 insertions(+) create mode 100644 exercises/concept/string-formatting/.docs/after.md create mode 100644 exercises/concept/string-formatting/.docs/hints.md create mode 100644 exercises/concept/string-formatting/.docs/instructions.md create mode 100644 exercises/concept/string-formatting/.docs/introduction.md create mode 100644 exercises/concept/string-formatting/.meta/Example.cs create mode 100644 exercises/concept/string-formatting/.meta/config.json create mode 100644 exercises/concept/string-formatting/.meta/design.md create mode 100644 exercises/concept/string-formatting/StringFormatting.cs create mode 100644 exercises/concept/string-formatting/StringFormatting.csproj create mode 100644 exercises/concept/string-formatting/StringFormattingTests.cs diff --git a/exercises/concept/string-formatting/.docs/after.md b/exercises/concept/string-formatting/.docs/after.md new file mode 100644 index 0000000000..8e1fe58a4b --- /dev/null +++ b/exercises/concept/string-formatting/.docs/after.md @@ -0,0 +1,131 @@ +Mechanisms for formatting strings are many and various in C#/.NET: everything from simple concatenation of objects through calls to the overridden `object.ToString()` method to use of [`ICustomFormatter`][custom-formatter] (not covered in this exercise). + +The two most common mechanisms for formatting strings are [string interpolation][string-interpolation] and [String.Format()][string-format]. The [`StringBuilder`][string-builder] (cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved. + +#### Using `ToString()` + +`System.Object()` from which all classes and structs inherit has a `ToString()` method. For example `new DateTime(2019, 5, 23).ToString()` will render "05/23/2019 00:00:00" (on a thread with US culture - [see below](#culture)). There are situations such as string concatenation where this default `ToString()` method may be invoked implicitly, `"" + new DateTime(2019, 5, 23)` gives the same result. + +In addition to the default `ToString()` method, types where formatting is an issue will have overloads which take a [_format string_](#bcl-formatters-and-format-strings) or even a [format provider][format-provider]. Notably in the BCL (Base Class Library) these are numbers, dates, enums and GUIDs. + +#### Composite Formatting + +`String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as a _format items_) and a variable number of arguments. The return value resolves each _format item_ using the corresponding argument and combines the resolved values with the fixed text. + +```csharp +string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25)) +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +`Format()` may be a better choice than interpolation where the format is being used in multiple expressions as a kind of template or where incorporating the format, and the expressions to be formatted is too cumbersome such as when [verbatim strings][verbatim-strings] are involved. + +This mechanism is technically known as [_composite formatting_][composite-formatting]. + +A fuller list of string producing methods that take advantage _composite formatting_ is given in this [article][composite-formatting]. + +#### String Interpolation + +Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{[,][:]}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism. + +The expression can comprise anything in scope. _Alignment_ is the length of the "field" in which the text sits. If the _alignment_ is positive then the text is padded with spaces on the left and if it is negative then the padding is to the right of the text. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password." +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +#### Format Items + +The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_. + +A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional _format string_ (introduced with a colon, ":"). + +`{[,][:]}` + +The _alignment_ specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is negative or to the right if it is positive. + +The _format string_ specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a `DateTime` object should be output. + +The following code illustrates display of the date portion of a `DateTime` object and a floating-point number in exponential form. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password." +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings + +string.Format( + "I had {0:E} bitcoins on {1:d}, the day I forgot my password.", + loadsOf, thatDay) +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings + +``` + +There is both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format characters. "custom" in this context has nothing to do with the [`ICustomFormatter`][custom-formatter] interface which is used when developing your own custom formatters. + +#### BCL Formatters and Format Strings + +The Base Class Library (BCL) provides 2 formatters: `DateTimeFormatInfo` and `NumberFormatInfo` and 6 groups of format strings. + +The various lists of _format strings_ are below: + +- [Standard numeric format strings][standard-numeric-format-strings] +- [Custom numeric format strings][custom-numeric-format-strings] +- [Standard date and time format strings][standard-date-and-time-format-strings] +- [Custom date and time format strings][custom-date-and-time-format-strings] +- [Enumeration format strings][enum-format-strings] +- [GUID format strings][guid-format-strings] + +`Enum` and `GUID` _format strings_ can be classed as _standard_. Although `enum` and `GUID` have `ToString()` overloads that take an `IFormatProvider` it is not clear that it does anything. + +An attempt is made in the library to instill some consistency into _format strings_ (beyond the fact that they are represented as strings). This push for consistency is found in the standard strings. In reality as a developer you rarely care about the difference between standard and custom strings. Although it is a good idea, if you are implementing formatters for your own classes to echo the existing standard strings if your classes appear to call for it, you can pretty well ignore the difference. + +#### Culture + +Each thread of execution has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted by default with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_. + +`CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture. + +#### Verbatim Strings + +[Verbatim strings][verbatim-strings] allow multi-line strings. They are introduced with an @. They can be used with string interpolation. Just add a "\$" before the opening quote. + +```csharp +string str = @" +See no wretched +quotes everywhere +"; +``` + +#### Reference Material + +- [String interpolation][string-interpolation]: tutorial on how to use string interpolation. +- [Formatting types][formatting-types]: the available format types to use. +- [Standard numeric format strings][standard-numeric-format-strings]: lists the standard numeric format strings. +- [Custom numeric format strings][custom-numeric-format-strings]: describes how to define custom numeric format strings. +- [Standard date and time format strings][standard-date-and-time-format-strings]: lists the standard date and time format strings. +- [Custom date and time format strings][custom-date-and-time-format-strings]: describes how to define custom date and time format strings. +- [String builder][string-builder]: shows how to use the string builder. +- [String interpolation - in-depth][string-interpolation-in-depth]: in-depth examination of string interpolation, including the generated IL code. +- [String interpolation - advanced][string-interpolation-advanced]: advanced tutorial on string interpolation, includes the `FormattableString` class. + +[string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +[string-interpolation-in-depth]: https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C# +[string-interpolation-advanced]: https://www.meziantou.net/interpolated-strings-advanced-usages.htm +[formatting-types]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types +[standard-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings +[custom-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings +[standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings +[string-builder]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/stringbuilder +[format-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.iformatprovider?view=netcore-3.1 +[custom-formatter]: https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1 +[string-format]: https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netcore-3.1#System_String_Format_System_String_System_Object_System_Object_System_Object_ +[verbatim-strings]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 +[composite-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting +[custom-string-interpolation]: https://thomaslevesque.com/2015/02/24/customizing-string-interpolation-in-c-6/ +[enum-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/enumeration-format-strings +[guid-format-strings]: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netcore-3.1 diff --git a/exercises/concept/string-formatting/.docs/hints.md b/exercises/concept/string-formatting/.docs/hints.md new file mode 100644 index 0000000000..9c933944ed --- /dev/null +++ b/exercises/concept/string-formatting/.docs/hints.md @@ -0,0 +1,37 @@ +## General + +- [String interpolation][string-interpolation]: tutorial on how to use string interpolation. +- [Formatting types][formatting-types]: the available format types to use. +- [Standard numeric format strings][standard-numeric-format-strings]: lists the standard numeric format strings. +- [Custom numeric format strings][custom-numeric-format-strings]: describes how to define custom numeric format strings. +- [Standard date and time format strings][standard-date-and-time-format-strings]: lists the standard date and time format strings. +- [Custom date and time format strings][custom-date-and-time-format-strings]: describes how to define custom date and time format strings. +- [`String.Format()`][string-format]: Library API. + +## 1. Display the couple's name separated by a heart + +- Take a look at the discussion of [string interpolation][string-interpolation]. + +## 2. Display the couple's initials in an ascii art heart + +- This [article][verbatim-strings] discusses verbatim strings literals. +- This [document][string-format] discusses `String.Format()`. + +## 3. German exchange students should be made to feel at home with locale-sensitive declarations. + +- To work with interpolated strings view the documentation for [`FormattableString`][formattable-string]. It may be better, to start with, to use [composite formatting][composite-formatting]. +- You will need to work with [`CultureInfo`][culture-info]. Note that it implements the [`IFormatProvider`][format-provider] interface. + +[string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +[format-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.iformatprovider?view=netcore-3.1 +[custom-formatter]: https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1 +[string-format]: https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netcore-3.1#System_String_Format_System_String_System_Object_System_Object_System_Object_ +[verbatim-strings]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 +[formattable-string]: https://docs.microsoft.com/en-us/dotnet/api/system.formattablestring?view=netcore-3.1 +[formatting-types]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types +[standard-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings +[custom-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings +[standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings +[composite-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting diff --git a/exercises/concept/string-formatting/.docs/instructions.md b/exercises/concept/string-formatting/.docs/instructions.md new file mode 100644 index 0000000000..9e2612ff3c --- /dev/null +++ b/exercises/concept/string-formatting/.docs/instructions.md @@ -0,0 +1,47 @@ +In this exercise, you are going to help high school sweethearts profess their love on social media. + +## 1. Display the couple's name separated by a heart + +Please implement the static `HighSchoolSweetheart.DisplaySingleLine()` method to take 2 names and display them separated by a heart centered in a 61 character line. + +All names are guaranteed to fit well within the width of the line. + +```csharp +HighSchoolSweetheart.DisplaySingleLine("Lance Green", "Pat Riley"); +// => " Lance Green ♡ Pat Riley " +``` + +## 2. Display the couple's initials in an ascii art heart + +Implement the static `HighSchoolSweetheart.DisplayBanner()` method which displays the two sets of initials separated with a plus sign. + +```csharp +HighSchoolSweetheart.DisplayBanner("L. G.", "P. R."); +// see the ascii art below +``` + +``` + ****** ****** + ** ** ** ** + ** ** ** ** +** * ** +** ** +** L. G. + P. R. ** + ** ** + ** ** + ** ** + ** ** + ** ** + ** ** + *** + * +``` + +## 3. German exchange students should be made to feel at home with locale-sensitive declarations. + +Implement the static `HighSchoolSweetheart.DisplayGermanExchangeStudents()` method to show date of start of relationship and length of time for our german exchange students. + +```csharp +HighSchoolSweetheart.DisplayGermanExchangeStudents("Norbert", "Heidi", new DateTime(2019, 1, 22), 1535.22f); +// => "Norbert and Heidi have been dating since 22.01.2019 - that's 1.535,22 hours" +``` diff --git a/exercises/concept/string-formatting/.docs/introduction.md b/exercises/concept/string-formatting/.docs/introduction.md new file mode 100644 index 0000000000..7ab55730c9 --- /dev/null +++ b/exercises/concept/string-formatting/.docs/introduction.md @@ -0,0 +1,68 @@ +There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation. + +## Composite Formatting + +`String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as format items), and a variable number of arguments. The return value resolves each format item using the corresponding argument and combines the resolved values with the fixed text. + +```csharp +string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25)); +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +This mechanism is technically known as _composite formatting_. + +## String Interpolation + +Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password." +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +## Format Items + +The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_. + +A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional _format string_ (introduced with a colon ":"). + +`{[,][:]` + +The _alignment_ specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is negative or to the right if it is positive. + +The _format string_ specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a `DateTime` object should be output. + +The following code illustrates display of the data portion of a `DateTime` object and a floating-point number in exponential form. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password." +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings + +string.Format( + "I had {0:E} bitcoins on {1:d}, the day I forgot my password.", + loadsOf, thatDay) +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings +``` + +There are both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format letters. + +## Culture + +Each thread has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_. + +`CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture. + +## Verbatim Strings + +Verbatim strings allow multi-line strings. They are introduced with an @. + +```csharp +string str = @" +See no wretched +quotes everywhere +"; +``` diff --git a/exercises/concept/string-formatting/.meta/Example.cs b/exercises/concept/string-formatting/.meta/Example.cs new file mode 100644 index 0000000000..2dd15993ef --- /dev/null +++ b/exercises/concept/string-formatting/.meta/Example.cs @@ -0,0 +1,43 @@ +using System; +using System.Globalization; + +public static class HighSchoolSweetheart +{ + private const string banner = + @" + ****** ****** + ** ** ** ** + ** ** ** ** +** * ** +** ** +** {0} + {1} ** + ** ** + ** ** + ** ** + ** ** + ** ** + ** ** + *** + * +"; + + public static string DisplaySingleLine(string studentA, string studentB) + { + const int lineLength = 61; + const int linePartLength = (lineLength - 1) / 2 - 1; + return $"{studentA,linePartLength} ♡ {studentB,-linePartLength}"; + } + + public static string DisplayBanner(string studentA, string studentB) + { + return string.Format(banner, studentA, studentB); + } + + public static string DisplayGermanExchangeStudents(string studentA + , string studentB, DateTime start, float hours) + { + FormattableString fs = + $"{studentA} and {studentB} have been dating since {start:d} - that's {hours:n2} hours"; + return fs.ToString(CultureInfo.CreateSpecificCulture("de-DE")); + } +} diff --git a/exercises/concept/string-formatting/.meta/config.json b/exercises/concept/string-formatting/.meta/config.json new file mode 100644 index 0000000000..1fa3647d97 --- /dev/null +++ b/exercises/concept/string-formatting/.meta/config.json @@ -0,0 +1,15 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "forked_from": ["elixir/strings"] +} diff --git a/exercises/concept/string-formatting/.meta/design.md b/exercises/concept/string-formatting/.meta/design.md new file mode 100644 index 0000000000..769846dbfd --- /dev/null +++ b/exercises/concept/string-formatting/.meta/design.md @@ -0,0 +1,26 @@ +## Learning objectives + +- Know how to use the `ToString()` method to convert any object to a `string`. +- Know how to use string interpolation on values of any type. +- Know how to use default format strings to convert to standard output formats. +- Know how to use custom format strings to convert to custom output formats. +- Know that `string.Format` underlies string interpolation. +- Know of the `StringBuilder` type and when to use it. +- Know that string interpolation can interpolate any expression. + +## Out of scope + +`IFormatProvider`, `ICustomFormatter` + +## Concepts + +- `string-formatting`: know how to use the `ToString()` method to convert any object to a `string`; know how to use string interpolation on values of any type; know how to use default format strings to convert to standard output formats; know how to use custom format strings to convert to custom output formats; know that `string.Format` underlies string interpolation; know of the `StringBuilder` type and when to use it; know that string interpolation can interpolate any expression. +- `verbatim-strings`: the syntax of verbatim strings. + +## Prerequisites + +- `strings`: strings will be formatted. +- `inheritance`: knowing that each class derives from `object` and thus has built-in methods. +- `const-readonly` +- `time`: for use of `CultureInfo`. +- `varargs`: for the common overload of `public static string Format (string format, params object[] args);` diff --git a/exercises/concept/string-formatting/StringFormatting.cs b/exercises/concept/string-formatting/StringFormatting.cs new file mode 100644 index 0000000000..8fee3825b4 --- /dev/null +++ b/exercises/concept/string-formatting/StringFormatting.cs @@ -0,0 +1,20 @@ +using System; + +public static class HighSchoolSweetheart +{ + public static string DisplaySingleLine(string studentA, string studentB) + { + throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplaySingleLine() method"); + } + + public static string DisplayBanner(string studentA, string studentB) + { + throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplayBanner() method"); + } + + public static string DisplayGermanExchangeStudents(string studentA + , string studentB, DateTime start, float hours) + { + throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplayGermanExchangeStudents() method"); + } +} diff --git a/exercises/concept/string-formatting/StringFormatting.csproj b/exercises/concept/string-formatting/StringFormatting.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/string-formatting/StringFormatting.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/string-formatting/StringFormattingTests.cs b/exercises/concept/string-formatting/StringFormattingTests.cs new file mode 100644 index 0000000000..6a62d36ebc --- /dev/null +++ b/exercises/concept/string-formatting/StringFormattingTests.cs @@ -0,0 +1,45 @@ +using System; +using Xunit; + +public class StringFormattingTests +{ + private const string expectedBanner = +@" + ****** ****** + ** ** ** ** + ** ** ** ** +** * ** +** ** +** L. G. + P. R. ** + ** ** + ** ** + ** ** + ** ** + ** ** + ** ** + *** + * +"; + [Fact] + public void DisplaySingleLine() + { + const string expected = " Lance Green ♡ Pat Riley "; + Assert.Equal(expected, HighSchoolSweetheart.DisplaySingleLine("Lance Green", "Pat Riley")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplayBanner() + { + string actualBanner = HighSchoolSweetheart.DisplayBanner("L. G. ", "P. R. "); + Assert.Equal(expectedBanner.Trim(), actualBanner.Trim()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void DisplayGermanExchangeStudents() + { + string actual = HighSchoolSweetheart.DisplayGermanExchangeStudents("Norbert", "Heidi", + new DateTime(2019, 1, 22), 1535.22f); + Assert.Equal("Norbert and Heidi have been dating since 22.01.2019 - that's 1.535,22 hours" + , actual); + } +} From 0e49e959b5c72f1d3c10ac5e549c30ce1bc5daff Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 21 Jul 2020 08:11:44 -0400 Subject: [PATCH 183/327] namespaces new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * namespaces initial commit * namespaces WIP * namespaces WIP * namespaces tweaks * namespaces typos * namespaces added examples * namespaces cleaning up docs * Apply suggestions from code review Co-authored-by: Erik Schierboom * namespaces review points * namespaces clean up * Apply suggestions from code review Co-authored-by: Erik Schierboom * namespaces finalizing * namespaces updated config.json Co-authored-by: Erik Schierboom --- exercises/concept/namespaces/.docs/after.md | 95 +++++++++++++++++++ exercises/concept/namespaces/.docs/hints.md | 16 ++++ .../concept/namespaces/.docs/instructions.md | 13 +++ .../concept/namespaces/.docs/introduction.md | 52 ++++++++++ exercises/concept/namespaces/.meta/Example.cs | 85 +++++++++++++++++ .../concept/namespaces/.meta/config.json | 14 +++ exercises/concept/namespaces/.meta/design.md | 19 ++++ exercises/concept/namespaces/Namespaces.cs | 78 +++++++++++++++ .../concept/namespaces/Namespaces.csproj | 13 +++ .../concept/namespaces/NamespacesTests.cs | 17 ++++ 10 files changed, 402 insertions(+) create mode 100644 exercises/concept/namespaces/.docs/after.md create mode 100644 exercises/concept/namespaces/.docs/hints.md create mode 100644 exercises/concept/namespaces/.docs/instructions.md create mode 100644 exercises/concept/namespaces/.docs/introduction.md create mode 100644 exercises/concept/namespaces/.meta/Example.cs create mode 100644 exercises/concept/namespaces/.meta/config.json create mode 100644 exercises/concept/namespaces/.meta/design.md create mode 100644 exercises/concept/namespaces/Namespaces.cs create mode 100644 exercises/concept/namespaces/Namespaces.csproj create mode 100644 exercises/concept/namespaces/NamespacesTests.cs diff --git a/exercises/concept/namespaces/.docs/after.md b/exercises/concept/namespaces/.docs/after.md new file mode 100644 index 0000000000..9be0dea34a --- /dev/null +++ b/exercises/concept/namespaces/.docs/after.md @@ -0,0 +1,95 @@ +It is unlikely that you will come across much production code that does not make use of namespaces. + +An example of the syntax is: + +```csharp +namespace MyNameSpace +{ + public class MyClass {} + + public class OtherClass {} +} +``` + +Namespaces are a way to group related code and to avoid name clashes. + +According to the [official documentation][namespaces] namespaces have two principal roles: + +- First, .NET uses namespaces to organize its many classes +- Second, declaring your own namespaces can help you control the scope of class and method names in larger programming projects. + +Namespaces are used widely by the base class library (BCL) to organize its functionality. + +#### References to namespaced types + +Types enclosed in namespaces are referred to outside the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and any types in the imported namespace can be used without the prefix. Within the same namespace there is no need to qualify type names. + +```csharp +namespace MySpace +{ + public class MyClass {} + + public class Foo + { + public void Bar() + { + var baz = new MyClass(); + } + } +} + +public class Qux +{ + public void Box() + { + var nux = new MySpace.MyClass(); + } +} + +namespace OtherSpace +{ + using MySpace; + + public class Tix + { + public void Jeg() + { + var lor = new MyClass(); + } + } +} +``` + +This [article][using] clearly explains the ways in which the `using` directive can be used: + +- `using`: avoid having to qualify types with namespace +- `using static`: avoid having to qualify members with types (a good example is `Math.Max()`). +- `using MyAlias = YourNamespace;`: substitute a more readable name for the namespace name. + +#### Clash of namespaces + +.NET addresses the issue of two namespaces with the same name in different assemblies where there would be a clash of fully qualified identifier names (perhaps a scenario where multiple versions of an assembly are loaded). This issue is addressed with the [namespace alias qualifier][namespace-alias-qualifier] and the [extern alias][extern-alias]. + +One reason to raise this fairly niche topic is because of its use of the [`::` operator][dot-dot-operator]. You will often see the qualifier `global::` prefixing namespaces, particularly in generated code. The intention here is to avoid a potential clash with some nested namespace or class name. By prefixing a namespace with `global::` you ensure that a top-level namespace is selected. + +#### Note for Java developers + +When comparing with the `import` of Java `packages` some differences and similarities should be noted: + +- There is no equivalent with C# of importing specific types. +- `using static` and `import static` are equivalent. +- In Java, package names have an impact on accessibility as between jars. In C# assemblies are paramount and belonging to the same namespace does not affect access level. +- The relationship between file system paths and fully qualified class names in Java is not reflected in C#'s namespaces although it is good practice where possible to give a file the same name as the principal class it contains. + +#### Reference + +- [Namespaces][namespaces]: how to define and import namespaces. +- [Accessibility levels][accessibility-levels]: use the `public/internal/private` access modifiers. + +[namespaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/ +[accessibility-levels]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels +[namespace-alias-qualifier]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier +[extern-alias]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias +[using]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive +[assemblies]: https://docs.microsoft.com/en-us/dotnet/standard/assembly/ +[dot-dot-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier diff --git a/exercises/concept/namespaces/.docs/hints.md b/exercises/concept/namespaces/.docs/hints.md new file mode 100644 index 0000000000..f22dc3dbe2 --- /dev/null +++ b/exercises/concept/namespaces/.docs/hints.md @@ -0,0 +1,16 @@ +## General + +- [Namespaces][namespaces]: how to define and import namespaces. +- [Accessibility levels][accessibility-levels]: use the `public/internal/private` access modifiers. + +## 1. Find a more appropriate way of isolating the code of the two teams + +- See this [article][namespaces] which discusses the syntax of namespaces. + +## 2. Simplify the naming system + +- See this [article][using] on the `using` directive. + +[namespaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/ +[accessibility-levels]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels +[using]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive diff --git a/exercises/concept/namespaces/.docs/instructions.md b/exercises/concept/namespaces/.docs/instructions.md new file mode 100644 index 0000000000..20754b7313 --- /dev/null +++ b/exercises/concept/namespaces/.docs/instructions.md @@ -0,0 +1,13 @@ +Management are starting to apply Darwinian principles to the Remote Control Car project (TODO cross-ref-tba). The developers have been split into two teams, _Red_ and _Blue_, and are tasked with improving the design independently of each other. They don't need to concern themselves with design decisions of the other team. + +You have been asked to take a look at the code and see how you can best combine the two efforts for testing purposes. + +## 1. Find a more appropriate way of isolating the code of the two teams + +Please use `namespaces` to better express the intention of the code. + +Currently, important types like `Motor` and `Telemetry`, not to mention `RemoteControlCar` itself, are nested within an enclosing static class, `RemoteControlCarTeam`. The only purpose of the enclosing class is to allow types with the same name to coexist in the program. That is better expressed by using a namespace. You will see in the next exercise that, for these purposes, a `namespace` has advantages over a `static class`. + +## 2. Simplify the naming system + +Whilst management are adamant that the teams should be called `RedRemoteControlCarTeam` and `BlueRemoteControlCarTeam` in the definitions, the names are rather cumbersome when referencing the teams. Find a way to use the shorter identifiers `Red` and `Blue` when building the cars. diff --git a/exercises/concept/namespaces/.docs/introduction.md b/exercises/concept/namespaces/.docs/introduction.md new file mode 100644 index 0000000000..ccfd49113a --- /dev/null +++ b/exercises/concept/namespaces/.docs/introduction.md @@ -0,0 +1,52 @@ +Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base. + +The syntax is as follows: + +```csharp +namespace MyNameSpace +{ + public class MyClass {} + + public class OtherClass {} +} +``` + +Types enclosed in namespaces are referred to outside the scope of the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and type can be used without the prefix. Within the same namespace there is no need to qualify type names. + +```csharp +namespace MySpace +{ + public class MyClass {} + + public class Foo + { + public void Bar() + { + var baz = new MyClass(); + } + } +} + +public class Qux +{ + public void Box() + { + var nux = new MySpace.MyClass(); + } +} + +namespace OtherSpace +{ + using MySpace; + + public class Tix + { + public void Jeg() + { + var lor = new MyClass(); + } + } +} +``` + +You can alias a namespace with the syntax `using MyAlias = MySpace;` and then use the alias anywhere that the namespace could be used. diff --git a/exercises/concept/namespaces/.meta/Example.cs b/exercises/concept/namespaces/.meta/Example.cs new file mode 100644 index 0000000000..e91ef4ccf5 --- /dev/null +++ b/exercises/concept/namespaces/.meta/Example.cs @@ -0,0 +1,85 @@ +namespace RedRemoteControlCarTeam +{ + public class RemoteControlCar + { + public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry, RunningGear runningGear) + { + } + // red members and API + } + + public class RunningGear + { + // red members and API + } + + public class Telemetry + { + // red members and API + } + + public class Chassis + { + // red members and API + } + + public class Motor + { + // red members and API + } +} + +namespace BlueRemoteControlCarTeam +{ + public class RemoteControlCar + { + public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry) + { + + } + // blue members and API + } + + public class Telemetry + { + // blue members and API + } + + public class Chassis + { + // blue members and API + } + + public class Motor + { + // blue members and API + } +} + +namespace Combined +{ + using Red = RedRemoteControlCarTeam; + using Blue = BlueRemoteControlCarTeam; + + public static class CarBuilder + { + public static Red.RemoteControlCar BuildRed() + { + return new Red.RemoteControlCar( + new Red.Motor(), + new Red.Chassis(), + new Red.Telemetry(), + new Red.RunningGear() + ); + } + + public static Blue.RemoteControlCar BuildBlue() + { + return new Blue.RemoteControlCar( + new Blue.Motor(), + new Blue.Chassis(), + new Blue.Telemetry() + ); + } + } +} diff --git a/exercises/concept/namespaces/.meta/config.json b/exercises/concept/namespaces/.meta/config.json new file mode 100644 index 0000000000..9212d455d1 --- /dev/null +++ b/exercises/concept/namespaces/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/namespaces/.meta/design.md b/exercises/concept/namespaces/.meta/design.md new file mode 100644 index 0000000000..558bea9b08 --- /dev/null +++ b/exercises/concept/namespaces/.meta/design.md @@ -0,0 +1,19 @@ +## Learning objectives + +- Know what namespaces are. +- Know how to import namespaces. + +## Out of scope + +- Assemblies. + +## Concepts + +- `namespaces`: know what namespaces are; know how to import namespaces. +- `accessibility`: know how to use access modifiers to limit access to elements. + +## Prerequisites + +- `classes`: know how to define a class and what the `public` and `private` access modifiers are. +- `inheritance`: know about the `protected` access modifier. +- `nested-types` diff --git a/exercises/concept/namespaces/Namespaces.cs b/exercises/concept/namespaces/Namespaces.cs new file mode 100644 index 0000000000..36970f2861 --- /dev/null +++ b/exercises/concept/namespaces/Namespaces.cs @@ -0,0 +1,78 @@ +public static class RedRemoteControlCarTeam +{ + public class RemoteControlCar + { + public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry, RunningGear runningGear) + { + } + // red members and API + } + + public class RunningGear + { + // red members and API + } + + public class Telemetry + { + // red members and API + } + + public class Chassis + { + // red members and API + } + + public class Motor + { + // red members and API + } +} +public static class BlueRemoteControlCarTeam +{ + public class RemoteControlCar + { + public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry) + { + + } + // blue members and API + } + + public class Telemetry + { + // blue members and API + } + + public class Chassis + { + // blue members and API + } + + public class Motor + { + // blue members and API + } +} + +public static class CarBuilder +{ + public static RedRemoteControlCarTeam.RemoteControlCar BuildRed() + { + return new RedRemoteControlCarTeam.RemoteControlCar( + new RedRemoteControlCarTeam.Motor(), + new RedRemoteControlCarTeam.Chassis(), + new RedRemoteControlCarTeam.Telemetry(), + new RedRemoteControlCarTeam.RunningGear() + ); + } + + public static BlueRemoteControlCarTeam.RemoteControlCar BuildBlue() + { + return new BlueRemoteControlCarTeam.RemoteControlCar( + new BlueRemoteControlCarTeam.Motor(), + new BlueRemoteControlCarTeam.Chassis(), + new BlueRemoteControlCarTeam.Telemetry() + ); + } +} diff --git a/exercises/concept/namespaces/Namespaces.csproj b/exercises/concept/namespaces/Namespaces.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/namespaces/Namespaces.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/namespaces/NamespacesTests.cs b/exercises/concept/namespaces/NamespacesTests.cs new file mode 100644 index 0000000000..5a33bb4b1a --- /dev/null +++ b/exercises/concept/namespaces/NamespacesTests.cs @@ -0,0 +1,17 @@ +using Combined; +using Xunit; + +public class NamespacesTests +{ + [Fact] + public void BuildRed() + { + Assert.NotNull(CarBuilder.BuildRed()); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void BuildBlue() + { + Assert.NotNull(CarBuilder.BuildBlue()); + } +} From a0cf957994ba6c571a3c4ea105ac95e909cb6ff6 Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 29 Jul 2020 07:51:38 -0400 Subject: [PATCH 184/327] minor enhancement to after.md --- exercises/concept/casting/.docs/after.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/casting/.docs/after.md b/exercises/concept/casting/.docs/after.md index c4638fd885..9745de8af6 100644 --- a/exercises/concept/casting/.docs/after.md +++ b/exercises/concept/casting/.docs/after.md @@ -17,7 +17,7 @@ int myInt = 1729; long myLong = myInt; ``` -There is no implicit conversion of a numeric (or string) expression to `bool`. +There is no implicit conversion of a numeric (or string) expression to `bool`. The Base Class Library (BCL) provides `Convert.ToBoolean()` for this purpose. An expression of type `char` can be implicitly cast to `int`. The cast in the opposite direction must be explicit. Not all values of `int` are valid utf 16 chars. From d6147f3e4446a28980da1043cb050adc57fcc1d6 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 31 Jul 2020 06:20:33 -0400 Subject: [PATCH 185/327] integral-numbers new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * integral-numbers initial upload * integral-numbers added code * integral-numbers added intro * integral-numbers added intro * integral-numbers WIP * integral-numbers instructions * integral-numbers tidying up * integral-numbers tidying up * Apply suggestions from code review Co-authored-by: Erik Schierboom * integral-numbers - review points and completion * integral-numbers - review points and completion * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - proofing * integral-numbers - added track config.json * Apply suggestions from code review Co-authored-by: Erik Schierboom * interfaces final review points * interfaces final review points Co-authored-by: Erik Schierboom --- .../concept/integral-numbers/.docs/after.md | 90 +++++++ .../concept/integral-numbers/.docs/hints.md | 17 ++ .../integral-numbers/.docs/instructions.md | 45 ++++ .../integral-numbers/.docs/introduction.md | 34 +++ .../concept/integral-numbers/.meta/Example.cs | 68 +++++ .../integral-numbers/.meta/config.json | 14 + .../concept/integral-numbers/.meta/design.md | 21 ++ .../integral-numbers/IntegralNumbers.cs | 14 + .../integral-numbers/IntegralNumbers.csproj | 13 + .../integral-numbers/IntegralNumbersTests.cs | 240 ++++++++++++++++++ 10 files changed, 556 insertions(+) create mode 100644 exercises/concept/integral-numbers/.docs/after.md create mode 100644 exercises/concept/integral-numbers/.docs/hints.md create mode 100644 exercises/concept/integral-numbers/.docs/instructions.md create mode 100644 exercises/concept/integral-numbers/.docs/introduction.md create mode 100644 exercises/concept/integral-numbers/.meta/Example.cs create mode 100644 exercises/concept/integral-numbers/.meta/config.json create mode 100644 exercises/concept/integral-numbers/.meta/design.md create mode 100644 exercises/concept/integral-numbers/IntegralNumbers.cs create mode 100644 exercises/concept/integral-numbers/IntegralNumbers.csproj create mode 100644 exercises/concept/integral-numbers/IntegralNumbersTests.cs diff --git a/exercises/concept/integral-numbers/.docs/after.md b/exercises/concept/integral-numbers/.docs/after.md new file mode 100644 index 0000000000..a233472422 --- /dev/null +++ b/exercises/concept/integral-numbers/.docs/after.md @@ -0,0 +1,90 @@ +C#, like many statically typed languages, provides a number of types that represent integers, each with its own [range of values][integral-numeric-types]. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types. + +Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1. + +Values of unsigned integral types are represented with a simple [base 2][wiki-binary] representation. Values of signed types use [2s complement][wiki-twos-complement] signed number representation. + +The multiplicity of integer types reflects machine architectures, in the size of registers, the size of CPU instruction arguments and the treatment of sign within the CPU. A value of type `long` uses 64 bits whereas a value of type `sbyte` uses 8 bits. In some cases there will be implications on CPU performance, memory usage and even disk usage (where selection of a smaller integer type will generally be beneficial). Selection of integer `type` can also be a rough and ready wsy of communicating information to other developers about the expected range of values. The `int` type is widely used as the default type where nothing special has been identified about the particular usage. The `long` or `ulong` is widely used as a simple identifier. The size of the type in bytes determines the range of values. + +The types discussed so far are _primitive_ types. Each is paired with a `struct` alias which implements fields (such as `MinValue`) and methods (such as `ToString()`) which are associated with the type. + +| Type | Struct | Width | Minimum | Maximum | +| -------- | -------- | ------ | -------------------------- | --------------------------- | +| `sbyte` | `SByte` | 8 bit | -128 | +127 | +| `short` | `Int16` | 16 bit | -32_768 | +32_767 | +| `int` | `Int32` | 32 bit | -2_147_483_648 | +2_147_483_647 | +| `long` | `Int64` | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 | +| `byte` | `Byte` | 8 bit | 0 | +255 | +| `ushort` | `UInt16` | 16 bit | 0 | +65_535 | +| `uint` | `UInt32` | 32 bit | 0 | +4_294_967_295 | +| `ulong` | `UInt64` | 64 bit | 0 | +18_446_744_073_709_551_615 | + +#### Casting + +A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (rhs) ensures that the value will fit within the range of the type being assigned to (lhs) then there is a simple assignment: + +```csharp +ulong ul; +uint ui = uint.MaxValue; +ul = ui; // no problem +``` + +On the other hand if the range of type being assigned from is not a subset of the assignee's range of values then a cast, `()` operation is required even if the particular value is within the assignee's range: + +```csharp +uint ui; +short s = 42; +ui = (uint)s; +``` + +In the above example, if the value lay instead outside the range of the assignee then an overflow would occur. See (TODO cross-ref-tba). + +The requirement for casting is determined by the two types involved rather than a particular value. + +The following paragraphs discuss the casting of integral types. (TODO cross-ref-tba casting) provides a broader discussion of casting and type conversion. See that documentation for a discussion of conversion between integral types and floating-point numbers, `char` and `bool`. + +##### Casting Primitive Types - Implicit + +C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. + +An implicit cast is not signified by any special syntax. + +##### Casting Primitive Types - Explicit + +Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. + +Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown. + +#### Casting Primitive Types - Examples + +```csharp +int largeInt = Int32.MaxValue; +int largeNegInt = Int32.MinValue; +ushort shortUnsignedInt = ushort.MaxValue; + +// implicit cast +int from_ushort = shortUnsignedInt; // 65535 +float from_int = largeInt; // -21474836E+09 + +// explicit cast +uint from_largeInt = (uint)largeInt; // 2147483647 +uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) + +``` + +#### Bit conversion + +The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes. + +#### Reference + +- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. +- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. + +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression +[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[wiki-twos-complement]: https://en.wikipedia.org/wiki/Two%27s_complement +[wiki-binary]: https://en.wikipedia.org/wiki/Binary_number +[sbyte]: https://docs.microsoft.com/en-us/dotnet/api/system.sbyte?view=netcore-3.1 diff --git a/exercises/concept/integral-numbers/.docs/hints.md b/exercises/concept/integral-numbers/.docs/hints.md new file mode 100644 index 0000000000..80779bd650 --- /dev/null +++ b/exercises/concept/integral-numbers/.docs/hints.md @@ -0,0 +1,17 @@ +## General + +- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. +- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. + +## 1. Encode an integral value ready to send + +- Conversion to a byte array is dealt with [here][bit-converter-get-bytes] + +## 2. Decode a received buffer + +- Converting from a byte array is discussed [here][bit-converter-to-type] + +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[bit-converter-get-bytes]: https://docs.microsoft.com/en-us/dotnet/api/system.bitconverter.getbytes?view=netcore-3.1 +[bit-converter-to-type]: https://docs.microsoft.com/en-us/dotnet/api/system.bitconverter.toint16?view=netcore-3.1 diff --git a/exercises/concept/integral-numbers/.docs/instructions.md b/exercises/concept/integral-numbers/.docs/instructions.md new file mode 100644 index 0000000000..ec485ae40c --- /dev/null +++ b/exercises/concept/integral-numbers/.docs/instructions.md @@ -0,0 +1,45 @@ +Work continues on the remote control car project. Bandwidth in the telemetry system is at a premium and you have been asked to implement a message protocol for communicating telemetry data. + +Data is transmitted in a buffer (byte array). When integers are sent, the size of the buffer is reduced by employing the protocol described below. + +Each value should be represented in the smallest possible integral type (types of `byte` and `sbyte` are not included as the saving would be trivial): + +| Min Value | Max Value | Type | +| -------------------------- | ------------------------- | -------- | +| 4,294,967,296 | 9,223,372,036,854,775,807 | `long` | +| -9,223,372,036,854,775,808 | -2,147,483,649 | `long` | +| 2,147,483,648 | 4,294,967,295 | `uint` | +| 65,536 | 2,147,483,647 | `int` | +| -2,147,483,648 | -32,769 | `int` | +| 0 | 65,535 | `ushort` | +| -32,768 | -1 | `short` | + +The value should be converted to the appropriate number of bytes for its assigned type. The complete buffer comprises a byte indicating the number of additional bytes in the buffer (_prefix byte_) followed by the bytes holding the integer (_payload bytes_). + +If the payload bytes represent a signed type (`short`, `int` or `long`) then the prefix byte should contain the length as a negative number. + +Only the prefix byte and the number of following bytes indicated by the prefix will be sent in the communication. Internally a 9 byte buffer is used (with trailing zeroes, as necessary) both by sending and receiving routines. + +## 1. Encode an integral value ready to send + +Please implement the static method `TelemetryBuffer.ToBuffer()` to encode a buffer taking the parameter passed to the method. + +```csharp +TelemetryBuffer.ToBuffer(5) +// => {0x2, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; +TelemetryBuffer.ToBuffer(Int32.MaxValue) +// => {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 }; +TelemetryBuffer.ToBuffer(-1) +// => {0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }; +``` + +## 2. Decode a received buffer + +Please implement the static method `TelemetryBuffer.FromBuffer()` to decode the buffer received and return the value in the form of a `long`. + +```csharp +TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 }) +// => 2147483647 +``` + +If the prefix byte is not one of -8, -4, -2, 2, 4 then 0 should be returned. diff --git a/exercises/concept/integral-numbers/.docs/introduction.md b/exercises/concept/integral-numbers/.docs/introduction.md new file mode 100644 index 0000000000..a134fd0930 --- /dev/null +++ b/exercises/concept/integral-numbers/.docs/introduction.md @@ -0,0 +1,34 @@ +C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types. + +The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits. + +Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1. + +| Type | Width | Minimum | Maximum | +| ------ | ------ | -------------------------- | --------------------------- | +| sbyte | 8 bit | -128 | +127 | +| short | 16 bit | -32_768 | +32_767 | +| int | 32 bit | -2_147_483_648 | +2_147_483_647 | +| long | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 | +| byte | 8 bit | 0 | +255 | +| ushort | 16 bit | 0 | +65_535 | +| uint | 32 bit | 0 | +4_294_967_295 | +| ulong | 64 bit | 0 | +18_446_744_073_709_551_615 | + +A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (lhs) ensures that the value will lie within the range of the type being assigned to (rhs) then there is a simple assignment: + +```csharp +uint ui = uint.MaxValue; +ulong ul = ui; // no problem +``` + +On the other hand if the range of type being assigned from is not a subset of the assignee's range of values then a cast, `()` operation is required even if the particular value is within the assignee's range: + +```csharp +short s = 42; +uint ui = (uint)s; +``` + +#### Bit conversion + +The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes. diff --git a/exercises/concept/integral-numbers/.meta/Example.cs b/exercises/concept/integral-numbers/.meta/Example.cs new file mode 100644 index 0000000000..29dd78745a --- /dev/null +++ b/exercises/concept/integral-numbers/.meta/Example.cs @@ -0,0 +1,68 @@ +using System; + +public static class TelemetryBuffer +{ + public static byte[] ToBuffer(long reading) + { + byte[] allBytes = new byte[9]; + + byte[] bytes; + if (reading > UInt32.MaxValue || reading < Int32.MinValue) + { + allBytes[0] = 0xf8; + bytes = BitConverter.GetBytes(reading); + bytes.CopyTo(allBytes, 1); + } + else if (reading > Int32.MaxValue) + { + allBytes[0] = 0x4; + bytes = BitConverter.GetBytes((uint)reading); + bytes.CopyTo(allBytes, 1); + } + else if (reading > UInt16.MaxValue || reading < Int16.MinValue) + { + allBytes[0] = 0xfc; + bytes = BitConverter.GetBytes((int) reading); + bytes.CopyTo(allBytes, 1); + } + else if (reading > Int16.MaxValue) + { + allBytes[0] = 0x2; + bytes = BitConverter.GetBytes((ushort) reading); + bytes.CopyTo(allBytes, 1); + } + else if (reading >= 0) + { + allBytes[0] = 0xfe; + bytes = BitConverter.GetBytes((ushort) reading); + bytes.CopyTo(allBytes, 1); + } + else + { + allBytes[0] = 0xfe; + bytes = BitConverter.GetBytes((short) reading); + bytes.CopyTo(allBytes, 1); + } + + return allBytes; + } + + public static long FromBuffer(byte[] buffer) + { + switch ((sbyte)buffer[0]) + { + case -8: + return BitConverter.ToInt64(buffer, 1); + case 4: + return BitConverter.ToUInt32(buffer, 1); + case -4: + return BitConverter.ToInt32(buffer, 1); + case 2: + return BitConverter.ToUInt16(buffer, 1); + case -2: + return BitConverter.ToInt16(buffer, 1); + default: + return 0; + } + } +} diff --git a/exercises/concept/integral-numbers/.meta/config.json b/exercises/concept/integral-numbers/.meta/config.json new file mode 100644 index 0000000000..9212d455d1 --- /dev/null +++ b/exercises/concept/integral-numbers/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/integral-numbers/.meta/design.md b/exercises/concept/integral-numbers/.meta/design.md new file mode 100644 index 0000000000..aacb3bcae4 --- /dev/null +++ b/exercises/concept/integral-numbers/.meta/design.md @@ -0,0 +1,21 @@ +## Learning objectives + +- Know of the difference between signed and unsigned integral types. +- Know of the existence of the integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long` and `ulong`. +- Know when to use which integral type. + +## Out of scope + +- BigInteger. +- Overflows. +- Nullable integral types. + +## Concepts + +- `integral-numbers`: know of the difference between signed and unsigned integral types; know of the existence of the integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long` and `ulong`; know when to use which integral type. +- `casting`: Understand casting of integral numeric types. + +## Prerequisites + +- `numbers`: define numbers and apply arithmetic and logic to them. +- `arrays`: byte array is used in the exercises. diff --git a/exercises/concept/integral-numbers/IntegralNumbers.cs b/exercises/concept/integral-numbers/IntegralNumbers.cs new file mode 100644 index 0000000000..36cdba9cca --- /dev/null +++ b/exercises/concept/integral-numbers/IntegralNumbers.cs @@ -0,0 +1,14 @@ +using System; + +public static class TelemetryBuffer +{ + public static byte[] ToBuffer(long reading) + { + throw new NotImplementedException("Please implement the static TelemetryBuffer.ToBuffer() method"); + } + + public static long FromBuffer(byte[] buffer) + { + throw new NotImplementedException("Please implement the static TelemetryBuffer.FromBuffer() method"); + } +} diff --git a/exercises/concept/integral-numbers/IntegralNumbers.csproj b/exercises/concept/integral-numbers/IntegralNumbers.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/integral-numbers/IntegralNumbers.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/integral-numbers/IntegralNumbersTests.cs b/exercises/concept/integral-numbers/IntegralNumbersTests.cs new file mode 100644 index 0000000000..3fb6748d1d --- /dev/null +++ b/exercises/concept/integral-numbers/IntegralNumbersTests.cs @@ -0,0 +1,240 @@ +using System; +using Xunit; + +namespace IntegralNumbers +{ + public class TelemetryBufferTests + { + [Fact] + public void ToBuffer_upper_long() + { + var bytes = TelemetryBuffer.ToBuffer(Int64.MaxValue); + Assert.Equal(new byte[] {0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_long() + { + var bytes = TelemetryBuffer.ToBuffer((long)UInt32.MaxValue + 1); + Assert.Equal(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_uint() + { + var bytes = TelemetryBuffer.ToBuffer(UInt32.MaxValue); + Assert.Equal(new byte[] {0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_uint() + { + var bytes = TelemetryBuffer.ToBuffer((long)Int32.MaxValue + 1); + Assert.Equal(new byte[] {0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_int() + { + var bytes = TelemetryBuffer.ToBuffer(Int32.MaxValue); + Assert.Equal(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_int() + { + var bytes = TelemetryBuffer.ToBuffer((long)UInt16.MaxValue + 1); + Assert.Equal(new byte[] {0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_ushort() + { + var bytes = TelemetryBuffer.ToBuffer(UInt16.MaxValue); + Assert.Equal(new byte[] {0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_ushort() + { + var bytes = TelemetryBuffer.ToBuffer((long)Int16.MaxValue + 1); + Assert.Equal(new byte[] {0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_short() + { + var bytes = TelemetryBuffer.ToBuffer(Int16.MaxValue); + Assert.Equal(new byte[] {0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_Zero() + { + var bytes = TelemetryBuffer.ToBuffer(0); + Assert.Equal(new byte[] {0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_neg_short() + { + var bytes = TelemetryBuffer.ToBuffer(-1); + Assert.Equal(new byte[] {0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_neg_short() + { + var bytes = TelemetryBuffer.ToBuffer(Int16.MinValue); + Assert.Equal(new byte[] {0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_neg_int() + { + int n = Int16.MinValue - 1; + var bytes = TelemetryBuffer.ToBuffer(n); + Assert.Equal(new byte[] {0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_neg_int() + { + var bytes = TelemetryBuffer.ToBuffer(Int32.MinValue); + Assert.Equal(new byte[] {0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_upper_neg_long() + { + var bytes = TelemetryBuffer.ToBuffer((long)Int32.MinValue - 1); + Assert.Equal(new byte[] {0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff }, bytes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void ToBuffer_lower_neg_long() + { + var bytes = TelemetryBuffer.ToBuffer(Int64.MinValue); + Assert.Equal(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 }, bytes); + } + + [Fact (Skip = "Remove this Skip property to run this test")] + public void FromBuffer_Invalid() + { + Assert.Equal(0, + TelemetryBuffer.FromBuffer(new byte[] {22, 0xff, 0xff, 0xff, 0x7f, 0, 0, 0, 0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_long() + { + Assert.Equal(Int64.MaxValue, + TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_long() + { + Assert.Equal((long)UInt32.MaxValue + 1, + TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_uint() + { + Assert.Equal(UInt32.MaxValue, + TelemetryBuffer.FromBuffer(new byte[] {0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0})); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_uint() + { + Assert.Equal((long)Int32.MaxValue + 1, + TelemetryBuffer.FromBuffer(new byte[] {0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_int() + { + Assert.Equal(Int32.MaxValue, + TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_int() + { + Assert.Equal(UInt16.MaxValue + 1, + TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_ushort() + { + Assert.Equal(UInt16.MaxValue, + TelemetryBuffer.FromBuffer(new byte[] {0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_ushort() + { + Assert.Equal(Int16.MaxValue + 1, + TelemetryBuffer.FromBuffer(new byte[] {0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_short() + { + Assert.Equal(Int16.MaxValue, + TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_Zero() + { + Assert.Equal(0, + TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_neg_short() + { + Assert.Equal(-1, + TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_neg_short() + { + Assert.Equal(Int16.MinValue, + TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_neg_int() + { + Assert.Equal(Int16.MinValue - 1, + TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_neg_int() + { + Assert.Equal(Int32.MinValue, + TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_upper_neg_long() + { + Assert.Equal((long)Int32.MinValue - 1, + TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff })); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void FromBuffer_lower_neg_long() + { + Assert.Equal(Int64.MinValue, + TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 })); + } + } +} From 9080deef66e3b3df8464f562fc3650e8ed8529b9 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 31 Jul 2020 08:47:18 -0400 Subject: [PATCH 186/327] interfaces new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * interfaces - copied from senal's branch - PR #1472 - all review points have been addressed * interfaces - coded * interfaces - WIP * interfaces - sample doc for review * interfaces - refinement * interfaces - refinement * interfaces - refinement * updated links * putting README.md straight * sorting out exercises.json * Merge branch 'interfaces' of github.com:mikedamay/v3 into interfaces # Conflicts: # languages/reference/README.md * Apply suggestions from code review Co-authored-by: Erik Schierboom * interfaces review points * interfaces post-review WIP * interfaces added test for IComparable * interfaces pre-finalization WIP * interfaces illustrates the two main use-cases. * interfaces after.md * interfaces after.md * interfaces after.md * interfaces introduction.md * interfaces introduction.md * interfaces WIP * interfaces WIP * interfaces WIP * interfaces proofing * interfaces proofing * Update languages/exercises/concept/interfaces/.docs/instructions.md Co-authored-by: Erik Schierboom * interfaces finalizing * interfaces config.json * Update languages/exercises/concept/interfaces/.docs/after.md Co-authored-by: Erik Schierboom Co-authored-by: Erik Schierboom --- exercises/concept/interfaces/.docs/after.md | 182 ++++++++++++++++++ exercises/concept/interfaces/.docs/hints.md | 21 ++ .../concept/interfaces/.docs/instructions.md | 45 +++++ .../concept/interfaces/.docs/introduction.md | 34 ++++ exercises/concept/interfaces/.meta/Example.cs | 53 +++++ .../concept/interfaces/.meta/config.json | 18 ++ exercises/concept/interfaces/.meta/design.md | 20 ++ exercises/concept/interfaces/Interfaces.cs | 42 ++++ .../concept/interfaces/Interfaces.csproj | 13 ++ .../concept/interfaces/InterfacesTests.cs | 42 ++++ 10 files changed, 470 insertions(+) create mode 100644 exercises/concept/interfaces/.docs/after.md create mode 100644 exercises/concept/interfaces/.docs/hints.md create mode 100644 exercises/concept/interfaces/.docs/instructions.md create mode 100644 exercises/concept/interfaces/.docs/introduction.md create mode 100644 exercises/concept/interfaces/.meta/Example.cs create mode 100644 exercises/concept/interfaces/.meta/config.json create mode 100644 exercises/concept/interfaces/.meta/design.md create mode 100644 exercises/concept/interfaces/Interfaces.cs create mode 100644 exercises/concept/interfaces/Interfaces.csproj create mode 100644 exercises/concept/interfaces/InterfacesTests.cs diff --git a/exercises/concept/interfaces/.docs/after.md b/exercises/concept/interfaces/.docs/after.md new file mode 100644 index 0000000000..bd3b08fa7b --- /dev/null +++ b/exercises/concept/interfaces/.docs/after.md @@ -0,0 +1,182 @@ +[`interfaces`][interfaces] are the primary means of [decoupling][wiki-loose-coupling] the uses of a class from its implementation. This decoupling provides flexibility for maintenance of the implementation and helps support type safe generic behavior. + +The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided. + +```csharp +public interface ILanguage +{ + string Speak(); +} + +public interface IItalianLanguage : ILanguage +{ + string Speak(); + string SpeakItalian(); +} + +public interface IScriptConverter +{ + string Version { get; set; } + string ConvertCyrillicToLatin(string cyrillic); +} +``` + +The implementing class or struct must implement all operations defined by the interface. + +Interfaces typically do one or more of the following: + +- allow a number of different classes to be treated generically by the using code. In this case interfaces are playing the same role as a base class +- expose a subset of functionality for some specific purpose (such as [`IComparable`][icomparable]) or +- expose the public API of a class so that multiple implementations can co-exist. One example is that of a [test double][wiki-test-double] + +```csharp +public class ItalianTraveller : IItalianLanguage +{ + public string Speak() + { + return "Ciao mondo"; + } + + public string SpeakItalian() + { + return Speak(); + } +} + +public class ItalianTravellerV2 : IItalianLanguage +{ + public string Speak() + { + return "migliorata - Ciao mondo"; + } + + public string SpeakItalisn() + { + return Speak(); + } +} + +public class FrenchTraveller : ILanguage +{ + public string Speak() + { + return "Ça va?"; + } +} + +public class RussianTraveller : ILanguage, IScriptConverter +{ + public string Version { get; set; } = "1.0"; + + public string Speak() + { + return "Привет мир"; + } + + public string ConvertCyrillicToLatin(string cyrillic) + { + throw new NotImplementedException(); + } +} + +public class DocumentTranslator : IScriptConverter +{ + public string Version { get; set; } = "1.0"; + + public string Translate(string russian) + { + throw new NotImplementedException(); + } + + public string ConvertCyrillicToLatin(string cyrillic) + { + throw new NotImplementedException(); + } +} +``` + +Code which uses the above interfaces and classes can: + +- treat all speakers in the same way irrespective of language. +- allow some subsystem handling script conversion to operate without caring about what specific types it is dealing with. +- remain unaware of the changes to the italian speaker which is convenient if the class code and user code are maintained by different teams + +Interfaces are widely used to support testing as they allow for easy [mocking][so-mocking-interfaces]. + +See this [article][dt-interfaces] for details of what types of member can be included in an interface. + +Interfaces can inherit from other interfaces. + +Members of an interface are public by default. + +Interfaces can contain nested types, such as `const` literals, `enums`, `delegates`, `classes` and `structs`. Here, the interfaces act as [namespaces][wiki-namespaces] in the same way that classes and structs do and the behaviour and syntax is identical. + +By design, C# does not support multiple inheritance, but it facilitates a kind of multiple inheritance through interfaces. + +Moreover, the concept of [polymorphism can be implemented through interfaces][interface-polymorphism] underpins the interface mechanism. + +#### Explicit interface implementation + +Sometimes method names and signatures can be shared in two different interfaces. +In order provide a distinct implementation of these methods, C# provides [explicit implementation of interfaces][explicit-implementation]. Note that to use a particular implementation of an interface you need to convert the expression containing referencing the object to that interface. Assignment, casting or passing as a parameter will achieve this. + +```csharp +public interface IFoo +{ + void X(); +} + +public interface IBar +{ + void X(); +} + +public class Census : IFoo, IBar +{ + void IFoo.X() + { + Console.Write("This is from Foo"); + } + + void IBar.X() + { + Console.Write("This is from Bar"); + } +} + +public class User +{ + public void Use() + { + IFoo foo = new Census(); + IBar bar = new Census(); + foo.X(); + // => "This is from Foo" + bar.X(); + // => "This is from Bar" + } +} +``` + +There are a number of use cases: + +- A clash of domains (as illustrated above) where methods have identical signatures. +- Methods with the same name but different return types: if you implement your own collection classes you may find that an explicit interface for the legacy `IEnumerable.GetEnumerator()`, alongside `IEnumerable.GetEnuerator()`, is required. You may never make use of such the interface but the compiler may insist. +- Methods where there is no clash of names between interfaces but it is desirable that the implementing class uses the name for some related purpose: `IFormattable` has a `ToString()` method which takes a _format type_ parameter as well as parameter of type `IFormatProvider`. A class like `FormattableString` from the Base Class Library (BCL) has the interface to ensure it can be used by routines that take an `IFormattable` but it is more expressive for its main version of `ToString(IFormatProvider)` to omit the _format type_ parameter as it is not used in the implementation and would confuse API users. + +#### Default implementation + +Version 8 of C# addresses a nagging problem with APIs. If you add methods to an interface to enhance functionality for new implementations then it is necessary to modify all the existing implementations of the interface so that they comply with the API-contract even though they have no implementation specific behavior. C# now allows for a _default method_ to be provided as part of the interface (Java developers will be familiar). Previously, when such a change occurred a _version 2_ of the interface would exist alongside the original. + +This [article][dt-interfaces] is an excellent primer on interfaces and focuses on _default implementation_ and other supporting innovations such as `static`, `private` and `virtual` members. + +[interface-polymorphism]: https://www.cs.utexas.edu/~mitra/csSummer2013/cs312/lectures/interfaces.html +[explicit-implementation]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation +[so-mocking-interfaces]: https://stackoverflow.com/a/9226437/96167 +[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 +[wiki-test-double]: https://en.wikipedia.org/wiki/Test_double +[wiki-polymorphism]: https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +[wiki-namespaces]: https://en.wikipedia.org/wiki/Namespace +[dt-interfaces]: https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/ +[wiki-loose-coupling]: https://en.wikipedia.org/wiki/Loose_coupling +[interfaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ diff --git a/exercises/concept/interfaces/.docs/hints.md b/exercises/concept/interfaces/.docs/hints.md new file mode 100644 index 0000000000..0c2096f63e --- /dev/null +++ b/exercises/concept/interfaces/.docs/hints.md @@ -0,0 +1,21 @@ +## General + +- [Interface][interface]: what an interface is and how to implement it. + +## 1. Enable cars to be driven on the same test track + +- This [article][interface] discusses interfaces and how to implement them. + +## 2. Enable the distance travelled by different models on the test track to be compared + +- The syntax for [properties][interface-property] on interfaces is discussed here. + +## 3. Allow the production cars to be ranked + +- See [this discussion][sort] of sorting. +- See [here][icomparable] for default comparison of objects. + +[interface]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ +[interface-property]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/interface-properties +[sort]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1.sort?view=netcore-3.1#System_Collections_Generic_List_1_Sort +[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 diff --git a/exercises/concept/interfaces/.docs/instructions.md b/exercises/concept/interfaces/.docs/instructions.md new file mode 100644 index 0000000000..d765431561 --- /dev/null +++ b/exercises/concept/interfaces/.docs/instructions.md @@ -0,0 +1,45 @@ +In this exercise you will be doing some more work on remote control cars. + +An experimental car has been developed and the test track needs to be adapted to handle both production and experimental models. The two types of car have already been built and you need to find a way to deal with them both on the test track. + +In addition, production cars are beginning to have some success. The team boss is keen to maintain the competitive spirit by publishing a ranking of the production cars. + +## 1. Enable cars to be driven on the same test track + +Please add a method to the `IRemoteControlCar` interface to expose the implementations of `Drive()` for the two types of car. + +```csharp +TestTrack.Race(new ProductionRemoteControlCar()); +TestTrack.Race(new ExperimentalRemoteControlCar()); +// this should execute without an exception being thrown +``` + +## 2. Enable the distance travelled by different models on the test track to be compared + +Please add a property to the `IRemoteControlCar` interface to expose the implementations of the `DistanceTravelled` property for the two types of car. + +```csharp +var prod = new ProductionRemoteControlCar(); +TestTrack.Race(prod); +var exp = new ExperimentalRemoteControlCar(); +TestTrack.Race(exp); +prod.DistanceTravelled +// => 10 +exp.DistanceTravelled +// => 20 +``` + +## 3. Allow the production cars to be ranked + +Please implement the `IComparable` interface in the `ProductionRemoteControlCar` class. The default sort order for cars should be ascending order of victories. + +Implement the static `TestTrack.GetRankedCars()` to return the cars passed is sorted in ascending order of number of victories. + +```csharp +var prc1 = new ProductionRemoteControlCar(); +var prc2 = new ProductionRemoteControlCar(); +prc1.NumberOfVictories = 3; +prc2.NumberOfVictories = 2; +var rankings = TestTrack.GetRankedCars(prc1, prc2); +// => rankings[1] == prc1 +``` diff --git a/exercises/concept/interfaces/.docs/introduction.md b/exercises/concept/interfaces/.docs/introduction.md new file mode 100644 index 0000000000..85377201d0 --- /dev/null +++ b/exercises/concept/interfaces/.docs/introduction.md @@ -0,0 +1,34 @@ +An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion. + +The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided. + +```csharp +public interface ILanguage +{ + string LanguageName { get; set; } + string Speak(); +} + +public class ItalianTaveller : ILanguage, ICloneable +{ + public string LanguageName { get; set; } = "Italiano"; + + public string Speak() + { + return "Ciao mondo"; + } + + public object Clone() + { + ItalianTaveller it = new ItalianTaveller(); + it.LanguageName = this.LanguageName; + return it; + } +} +``` + +All operations defined by the interface must be implemented. + +Interfaces can contain instance methods and properties amongst other members + +The `IComparable` interface can be implemented where a default generic sort order in collections is required. diff --git a/exercises/concept/interfaces/.meta/Example.cs b/exercises/concept/interfaces/.meta/Example.cs new file mode 100644 index 0000000000..6266723e50 --- /dev/null +++ b/exercises/concept/interfaces/.meta/Example.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +public interface IRemoteControlCar +{ + void Drive(); + int DistanceTravelled { get; } +} + +public class ProductionRemoteControlCar : IRemoteControlCar, IComparable +{ + public int DistanceTravelled { get; private set; } + public int NumberOfVictories { get; set; } + + public void Drive() + { + DistanceTravelled += 10; + } + + public int CompareTo(ProductionRemoteControlCar other) + { + if (ReferenceEquals(this, other)) return 0; + if (ReferenceEquals(null, other)) return 1; + return NumberOfVictories.CompareTo(other.NumberOfVictories); + } +} + +public class ExperimentalRemoteControlCar : IRemoteControlCar +{ + public int DistanceTravelled { get; private set; } + + public void Drive() + { + DistanceTravelled += 20; + } +} + +public static class TestTrack +{ + public static decimal Race(IRemoteControlCar car) + { + car.Drive(); + return car.DistanceTravelled; + } + + public static List GetRankedCars(ProductionRemoteControlCar prc1, + ProductionRemoteControlCar prc2) + { + var rankings = new List{prc1, prc2}; + rankings.Sort(); + return rankings; + } +} diff --git a/exercises/concept/interfaces/.meta/config.json b/exercises/concept/interfaces/.meta/config.json new file mode 100644 index 0000000000..b367d9cb3c --- /dev/null +++ b/exercises/concept/interfaces/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "senal", + "exercism_username": "senal" + }, + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/interfaces/.meta/design.md b/exercises/concept/interfaces/.meta/design.md new file mode 100644 index 0000000000..1c8070c179 --- /dev/null +++ b/exercises/concept/interfaces/.meta/design.md @@ -0,0 +1,20 @@ +## Learning objectives + +- Know what interfaces are. +- Know how to use interfaces. +- Know how to define an interface. +- Know how to explicitly implement an interface (discussion only). +- Default interface implementations (discussion only). + +## Out of scope + +## Concepts + +- `interfaces`: know what interfaces are; know how to use interfaces; know how to define an interface; know how to implement an interface; know how to explicitly implement an interface. +- `ordering` : know how to implement the `IComparable` interface and what its effect is on the behaviour of collections. + +## Prerequisites + +- `classes`: know how to work with classes. +- `properties`: know what properties are. +- `lists`: know how to use `List`. diff --git a/exercises/concept/interfaces/Interfaces.cs b/exercises/concept/interfaces/Interfaces.cs new file mode 100644 index 0000000000..befb12ee51 --- /dev/null +++ b/exercises/concept/interfaces/Interfaces.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; + +public interface IRemoteControlCar +{ + // TODO implement the IRemoteControlCar interface +} + +public class ProductionRemoteControlCar +{ + public int DistanceTravelled { get; private set; } + public int NumberOfVictories { get; set; } + + public void Drive() + { + DistanceTravelled += 10; + } +} + +public class ExperimentalRemoteControlCar +{ + public int DistanceTravelled { get; private set; } + + public void Drive() + { + DistanceTravelled += 20; + } +} + +public static class TestTrack +{ + public static int Race(IRemoteControlCar car) + { + throw new NotImplementedException($"Please implement the (static) TestTrack.Race() method"); + } + + public static List GetRankedCars(ProductionRemoteControlCar prc1, + ProductionRemoteControlCar prc2) + { + throw new NotImplementedException($"Please implement the (static) TestTrack.GetRankedCars() method"); + } +} diff --git a/exercises/concept/interfaces/Interfaces.csproj b/exercises/concept/interfaces/Interfaces.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/interfaces/Interfaces.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/interfaces/InterfacesTests.cs b/exercises/concept/interfaces/InterfacesTests.cs new file mode 100644 index 0000000000..4a136447f7 --- /dev/null +++ b/exercises/concept/interfaces/InterfacesTests.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using Xunit; + +public class InterfacesTests +{ + [Fact] + public void Race() + { + var productionCar = new ProductionRemoteControlCar(); + var experimentalCar = new ExperimentalRemoteControlCar(); + TestTrack.Race((IRemoteControlCar)productionCar); + TestTrack.Race((IRemoteControlCar)productionCar); + TestTrack.Race((IRemoteControlCar)experimentalCar); + TestTrack.Race((IRemoteControlCar)experimentalCar); + Assert.Equal(20, experimentalCar.DistanceTravelled - productionCar.DistanceTravelled); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void RankCars() + { + var prc1 = new ProductionRemoteControlCar(); + var prc2 = new ProductionRemoteControlCar(); + prc1.NumberOfVictories = 3; + prc2.NumberOfVictories = 2; + var rankings = TestTrack.GetRankedCars(prc1, prc2); + Assert.Same(prc1, rankings[1]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void EnsureCarsAreComparable() + { + var fast = new ProductionRemoteControlCar(); + var medium = new ProductionRemoteControlCar(); + var slow = new ProductionRemoteControlCar(); + fast.NumberOfVictories = 3; + medium.NumberOfVictories = 2; + slow.NumberOfVictories = 1; + var cars = new List {fast, slow, medium}; + cars.Sort(); + Assert.Equal(new ProductionRemoteControlCar[] {slow, medium, fast}, cars); + } +} From 16d493cec54633ddec7ec993356f2af000905b2b Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 6 Aug 2020 09:05:44 -0400 Subject: [PATCH 187/327] operator-overloading new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * operator-overloading initial commit * operator-overloading pre-PR * operator-overloading WIP * nested-types code, instructions and introduction added * nested-types code, instructions and introduction added * nested-types sample tests * operator-overloading typo * operator-overloading tweaks * operator-overloading added design.md and after.md * Update languages/exercises/concept/operator-overloading/.docs/introduction.md Co-authored-by: Erik Schierboom * operator-overloading review points * operator-overloading review points * operator-overloading review points * operator-overloading review points * Apply suggestions from code review Co-authored-by: Erik Schierboom * operator-overloading late review points * operator-overloading added config.json Co-authored-by: Erik Schierboom --- .../operator-overloading/.docs/after.md | 81 +++++++++++++++ .../operator-overloading/.docs/hints.md | 30 ++++++ .../.docs/instructions.md | 85 ++++++++++++++++ .../.docs/introduction.md | 15 +++ .../operator-overloading/.meta/Example.cs | 99 +++++++++++++++++++ .../operator-overloading/.meta/config.json | 14 +++ .../operator-overloading/.meta/design.md | 16 +++ .../OperatorOverloading.cs | 19 ++++ .../OperatorOverloading.csproj | 13 +++ .../OperatorOverloadingTests.cs | 28 ++++++ 10 files changed, 400 insertions(+) create mode 100644 exercises/concept/operator-overloading/.docs/after.md create mode 100644 exercises/concept/operator-overloading/.docs/hints.md create mode 100644 exercises/concept/operator-overloading/.docs/instructions.md create mode 100644 exercises/concept/operator-overloading/.docs/introduction.md create mode 100644 exercises/concept/operator-overloading/.meta/Example.cs create mode 100644 exercises/concept/operator-overloading/.meta/config.json create mode 100644 exercises/concept/operator-overloading/.meta/design.md create mode 100644 exercises/concept/operator-overloading/OperatorOverloading.cs create mode 100644 exercises/concept/operator-overloading/OperatorOverloading.csproj create mode 100644 exercises/concept/operator-overloading/OperatorOverloadingTests.cs diff --git a/exercises/concept/operator-overloading/.docs/after.md b/exercises/concept/operator-overloading/.docs/after.md new file mode 100644 index 0000000000..d0fb4ff52b --- /dev/null +++ b/exercises/concept/operator-overloading/.docs/after.md @@ -0,0 +1,81 @@ +The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_. + +This [article][operator-overloading] is a thorough discussion of the syntax as well as which operators can be overloaded and those that can't. + +Most operators have the form: + +```csharp +static operaator (); +``` + +[Cast operators][ud-conversion-operators] have the form: + +```csharp +static (explicit|implicit) operator ( ); +``` + +Operators behave in the same way as static methods. + +- An operator symbol takes the place of a method identifier, and they have parameters and a return type. The type rules for parameters and return type follow your intuition and you can rely on the compiler to provide detailed guidance. +- For binary operations the first parameter takes the left-hand argument to the operation. +- Operators have a signature comprising two parameters (in the case of binary operations) and a return type or a single parameter and return type in the case of unary operators. +- For binary operators, one of the parameter types must be that of the declaring class. +- In the case of type conversions either the parameter or the return type must be the type of the declaring class. +- For incrementing and decrementing operators the parameter and return type must be that of the declaring class. + +Syntax examples: + +```csharp +struct Point +{ + decimal x; + decimal y; + + public static bool operator ==(Point pt, Point ptOther) + { + return pt.x == ptOther.x && pt.y == ptOther.y; + } + + public static bool operator !=(Point pt, Point ptOther) + { + return !(pt == ptOther); + } + + public static Point operator *(Point pt, decimal scale) + { + var ptNew = new Point(); + ptNew.x = pt.x * scale; + ptNew.y = pt.y * scale; + return ptNew; + } + + public static implicit operator Point((decimal x, decimal y) xy) + { + var pt = new Point(); + pt.x = xy.x; + pt.y = xy.y; + return pt; + } + + public static explicit operator (decimal x, decimal y)(Point pt) + { + return (pt.x, pt.y); + } +} +``` + +It is often productive to implement an [`Equals()`][equals] method and call it from the `==` operator. Similarly, for comparisons you can implement the [`IComparable`][icomparable] interface. In both cases you get to kill two birds with just over one stone. + +You should note that you cannot create operators from symbols that are not part of the standard set of operators. You can use only existing symbols for those operations where the documentation specifies that they can be overloaded. The operators that can be overloaded are listed [here][overloadable-operators]. + +Note that the order of parameters is important where they differ in type. In the above example code `pt * 10m` is a legal expression whereas `10m * pt` will not compile. + +#### Reference + +This documentation of [operator overloading][operator-overloading] details the syntax. + +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[ud-conversion-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators +[overloadable-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading#overloadable-operators +[equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ +[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 diff --git a/exercises/concept/operator-overloading/.docs/hints.md b/exercises/concept/operator-overloading/.docs/hints.md new file mode 100644 index 0000000000..7f9f1b6615 --- /dev/null +++ b/exercises/concept/operator-overloading/.docs/hints.md @@ -0,0 +1,30 @@ +## General + +- This documentation of [operator overloading][operator-overloading] details the syntax. + +## 1. Enable the currency amount to be tested for equality + +- See [this][operator-overloading] for equality operators. + +## 2. Compare currency amounts + +- See [this][operator-overloading] for comparison operators. + +## 3. Add and subtract currency amounts + +- See [this][operator-overloading] for sum and difference operators. + +## 4. Multiply and divide currency amounts + +- See [this][operator-overloading] for product and division operators. + +## 5. Convert the currency amount to a double + +- See [this][ud-conversion-operators] for conversion operators. + +## 5. Convert the currency amount to a decimal + +- See [this][ud-conversion-operators] for conversion operators. + +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[ud-conversion-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators diff --git a/exercises/concept/operator-overloading/.docs/instructions.md b/exercises/concept/operator-overloading/.docs/instructions.md new file mode 100644 index 0000000000..3f214ecc4b --- /dev/null +++ b/exercises/concept/operator-overloading/.docs/instructions.md @@ -0,0 +1,85 @@ +You've been tempted back to Hyperia (with the high inflation) for an eye watering daily rate. + +The Central Bank is contemplating introducing the US Dollar as a second currency so all the accounting systems have to be adapted to handle multiple currencies. + +You have been asked to implement the currency amount object. + +## 1. Enable the currency amount to be tested for equality + +Please modify the `CurrencyAmount` struct to handle equality. If the two currency amount structs do not have the same currency ("USD" or "HD") then an instance of `ArgumentException` should be thrown. + +```csharp +CurrencyAmount amountA = new CurrencyAmount(55, "HD"); +CurrencyAmount amountB = new CurrencyAmount(55, "HD"); +CurrencyAmount amountC = new CurrencyAmount(55, "USD"); +amountA == amountB +// => true +amountA != amountB +// => false +amountA == amountC +// => ArgumentException +amountA != amountC +// => ArgumentException +``` + +## 2. Compare currency amounts + +Please modify the `CurrencyAmount` struct to handle comparisons (`>` and `<`, only). If the two currency amount structs do not have the same currency ("USD" or "HD") then an instance of `ArgumentException` should be thrown. + +```csharp +CurrencyAmount amountA = new CurrencyAmount(55, "HD"); +amountA > new CurrencyAmount(50, "HD") +// => true +amountA < new CurrencyAmount(50, "HD") +// => false +amountA > new CurrencyAmount(50, "USD") +// => ArgumentException +``` + +## 3. Add and subtract currency amounts + +Please modify the `CurrencyAmount` struct to handle arithmetic addition and subtraction (`+` and `-`, only). If the two currency amount structs do not have the same currency ("USD" or "HD") then an instance of `ArgumentException` should be thrown. + +```csharp +CurrencyAmount amountA = new CurrencyAmount(55, "HD"); +CurrencyAmount amountB = new CurrencyAmount(100, "HD"); +CurrencyAmount amountC = new CurrencyAmount(55, "USD"); +amountA + amountB +// => {155, HD} +amountB - amountA +// => {45, HD} +amountA + amountC +// => ArgumentException +``` + +## 4. Multiply and divide currency amounts + +Please modify the `CurrencyAmount` struct to handle arithmetic multiplication and division (`*` and `/`, only). + +```csharp +CurrencyAmount amountA = new CurrencyAmount(10, "HD"); +amountA * 2m +// => {20, HD} +amountA / 2m +// => {5, HD} +``` + +## 5. Convert the currency amount to a double + +Please modify the `CurrencyAmount` struct so that an instance can be explicitly cast to a `double`. + +```csharp +CurrencyAmount amountA = new CurrencyAmount(55.5m, "HD"); +(double)amountA +// => 55.5d +``` + +## 6. Convert the currency amount to a decimal + +Please modify the `CurrencyAmount` struct so that an instance can be implicitly converted to a `decimal`. + +```csharp +CurrencyAmount amountA = new CurrencyAmount(55.5m, "HD"); +decimal d = amountA; +// => d == 55.5m +``` diff --git a/exercises/concept/operator-overloading/.docs/introduction.md b/exercises/concept/operator-overloading/.docs/introduction.md new file mode 100644 index 0000000000..daf28dc8cf --- /dev/null +++ b/exercises/concept/operator-overloading/.docs/introduction.md @@ -0,0 +1,15 @@ +The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_. + +Most operators have the form: + +```csharp +static operaator (); +``` + +Cast operators have the form: + +```csharp +static (explicit|implicit) operator ( ); +``` + +Operators behave in the same way as static methods. An operator symbol takes the place of a method identifier, and they have parameters and a return type. The type rules for parameters and return type follow your intuition and you can rely on the compiler to provide detailed guidance. diff --git a/exercises/concept/operator-overloading/.meta/Example.cs b/exercises/concept/operator-overloading/.meta/Example.cs new file mode 100644 index 0000000000..d231242df6 --- /dev/null +++ b/exercises/concept/operator-overloading/.meta/Example.cs @@ -0,0 +1,99 @@ +using System; +using System.Runtime.InteropServices; + +public struct CurrencyAmount +{ + private decimal amount; + private string currency; + + public CurrencyAmount(decimal amount, string currency) + { + this.amount = amount; + this.currency = currency; + } + + public static bool operator ==(CurrencyAmount @this, CurrencyAmount other) + { + if (@this.currency != other.currency) + { + throw new ArgumentException(); + } + + return @this.amount == other.amount; + } + + public static bool operator !=(CurrencyAmount @this, CurrencyAmount other) + { + return @this != other; + } + + public static bool operator >(CurrencyAmount @this, CurrencyAmount other) + { + if (@this.currency != other.currency) + { + throw new ArgumentException(); + } + + return @this.amount > other.amount; + } + + public static bool operator <(CurrencyAmount @this, CurrencyAmount other) + { + if (@this.currency != other.currency) + { + throw new ArgumentException(); + } + + return @this.amount < other.amount; + } + + public static CurrencyAmount operator +(CurrencyAmount @this, CurrencyAmount other) + { + if (@this.currency != other.currency) + { + throw new ArgumentException(); + } + + return new CurrencyAmount(@this.amount + other.amount, @this.currency); + } + + public static CurrencyAmount operator -(CurrencyAmount @this, CurrencyAmount other) + { + if (@this.currency != other.currency) + { + throw new ArgumentException(); + } + + return new CurrencyAmount(@this.amount - other.amount, @this.currency); + } + + public static CurrencyAmount operator *(CurrencyAmount @this, decimal multiplier) + { + return new CurrencyAmount(@this.amount * multiplier, @this.currency); + } + + public static CurrencyAmount operator *(decimal multiplier, CurrencyAmount @this) + { + return new CurrencyAmount(@this.amount * multiplier, @this.currency); + } + + public static CurrencyAmount operator /(CurrencyAmount @this, decimal divisor) + { + return new CurrencyAmount(@this.amount / divisor, @this.currency); + } + + public static CurrencyAmount operator /(decimal divisor, CurrencyAmount @this) + { + return new CurrencyAmount(@this.amount / divisor, @this.currency); + } + + public static explicit operator double (CurrencyAmount @this) + { + return (double) @this.amount; + } + + public static implicit operator decimal (CurrencyAmount @this) + { + return @this.amount; + } +} diff --git a/exercises/concept/operator-overloading/.meta/config.json b/exercises/concept/operator-overloading/.meta/config.json new file mode 100644 index 0000000000..9212d455d1 --- /dev/null +++ b/exercises/concept/operator-overloading/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/operator-overloading/.meta/design.md b/exercises/concept/operator-overloading/.meta/design.md new file mode 100644 index 0000000000..4d50b37c78 --- /dev/null +++ b/exercises/concept/operator-overloading/.meta/design.md @@ -0,0 +1,16 @@ +## Learning objectives + +- Know how and why to use standard C# operators in your own classes +- Understand the behavior of `==` and `!=` + +## Out of scope + +## Concepts + +- `operator-overloading`: know when to how and why to overload operators for your own classes; understand the syntax of equality, comparison and arithmetic operators; know the syntax of user defined type conversion; know which operators cannot be overloaded + +## Prerequisites + +- `method-overloading` +- `equality` +- `floating-point-numbers` diff --git a/exercises/concept/operator-overloading/OperatorOverloading.cs b/exercises/concept/operator-overloading/OperatorOverloading.cs new file mode 100644 index 0000000000..ed94d194e0 --- /dev/null +++ b/exercises/concept/operator-overloading/OperatorOverloading.cs @@ -0,0 +1,19 @@ +public struct CurrencyAmount +{ + private decimal amount; + private string currency; + + public CurrencyAmount(decimal amount, string currency) + { + this.amount = amount; + this.currency = currency; + } + + // TODO: implement equality operators + + // TODO: implement comparison operators + + // TODO: implement arithmetic operators + + // TODO: implement type conversion operators +} diff --git a/exercises/concept/operator-overloading/OperatorOverloading.csproj b/exercises/concept/operator-overloading/OperatorOverloading.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/operator-overloading/OperatorOverloading.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/operator-overloading/OperatorOverloadingTests.cs b/exercises/concept/operator-overloading/OperatorOverloadingTests.cs new file mode 100644 index 0000000000..8ed902de43 --- /dev/null +++ b/exercises/concept/operator-overloading/OperatorOverloadingTests.cs @@ -0,0 +1,28 @@ +using System; +using Xunit; + +public class OperatorOverloadingTests +{ + [Fact] + public void Equality_true() + { + Assert.True(Eq(new CurrencyAmount(55, "HD"), new CurrencyAmount(55, "HD"))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Equality_false() + { + Assert.False(Eq(new CurrencyAmount(55, "HD"), new CurrencyAmount(60, "HD"))); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Equality_bad() + { + Assert.Throws(() => Eq(new CurrencyAmount(55, "HD"), new CurrencyAmount(60, "USD"))); + } + + private bool Eq(CurrencyAmount amountA, CurrencyAmount amountB) + { + return amountA == amountB; + } +} From b81dde720dc1df07cd42dd2b5e0f2d9d8b584757 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 6 Aug 2020 09:18:13 -0400 Subject: [PATCH 188/327] expression-bodied-members new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * expression-bodied-members initial commit * expression-bodied-members pre-draft complete * expression-bodied-members pre-draft complete * operator-overloading added code * operator-overloading added code * expression-bodied-members draft PR * expression-bodied-members draft PR * expression-bodied-members - typos * expression-bodied-members - tweaks * expression-bodied-members misspelling s/be prerequisites * expression-bodied-members review points * expression-bodied-members review points * expression-bodied-members review points * expression-bodied-members review points * expression-bodied-members proofing * expression-bodied-members proofing * expression-bodied-members proofing * expression-bodied-members proofing * expression-bodied-members proofing * expression-bodied-members proofing * Apply suggestions from code review Co-authored-by: Erik Schierboom * expression-bodied-members late review points * expression-bodied-members added config.json Co-authored-by: Erik Schierboom --- .../expression-bodied-members/.docs/after.md | 74 ++++++++ .../expression-bodied-members/.docs/hints.md | 11 ++ .../.docs/instructions.md | 9 + .../.docs/introduction.md | 47 +++++ .../.meta/Example.cs | 95 ++++++++++ .../.meta/config.json | 14 ++ .../expression-bodied-members/.meta/design.md | 31 ++++ .../ExpressionBodiedMembers.cs | 172 ++++++++++++++++++ .../ExpressionBodiedMembers.csproj | 13 ++ .../ExpressionBodiedMembersTests.cs | 137 ++++++++++++++ 10 files changed, 603 insertions(+) create mode 100644 exercises/concept/expression-bodied-members/.docs/after.md create mode 100644 exercises/concept/expression-bodied-members/.docs/hints.md create mode 100644 exercises/concept/expression-bodied-members/.docs/instructions.md create mode 100644 exercises/concept/expression-bodied-members/.docs/introduction.md create mode 100644 exercises/concept/expression-bodied-members/.meta/Example.cs create mode 100644 exercises/concept/expression-bodied-members/.meta/config.json create mode 100644 exercises/concept/expression-bodied-members/.meta/design.md create mode 100644 exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs create mode 100644 exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj create mode 100644 exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs diff --git a/exercises/concept/expression-bodied-members/.docs/after.md b/exercises/concept/expression-bodied-members/.docs/after.md new file mode 100644 index 0000000000..9af1699ba5 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.docs/after.md @@ -0,0 +1,74 @@ +Many [types of struct and class members][expression-bodied-members] (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements. + +```csharp +public int Times3(int input) => input * 3; + +public int Interesting => 1729; +``` + +Expression-bodied-members cannot have blocks of multiple statements, but those with a functional background should be warned that anything that a traditional member can do can be achieved by one of these members. The "expression" can be an assignment operation creating side effects, or a method invocation meaning that anything is possible. + +#### Ternary Operators + +[Ternary operators][ternary-operators] allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone. + +The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`). + +```csharp +int a = 3, b = 4; +int max = a > b ? a : b; +// => 4 +``` + +#### Switch expression + +[Switch expressions][switch-expressions] behave in a similar manner to [switch statements][switch-statements] covered in (TODO cross-ref-tba switch statements). They support a kind of decision table that maps input conditions to actions or values. + +At the core of the switch expression is _pattern matching_. In the coding exercise we matched values against `const` patterns. In this case the inputs to the `switch` are a _range expression_ which is matched to const values and the values used by the _case guards_. + +The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found. + +The `_` case which is the last in the list is useful to ensure that the matching is exhaustive and to avoid possible run-time errors. + +```csharp +double xx = 42d; + +string interesting = xx switch +{ + 0 => "I suppose zero is interesting", + 3.14 when DateTime.Now.Day == 14 && DateTime.Now.Month == 3 => "Mmm pie!", + 3.14 => "π", + 42 => "a bit of a cliché", + 1729 => "only if you are a pure mathematician", + _ => "not interesting" +}; + +// => interesting == "a bit of a cliché" +``` + +An "arm" of the `switch` is selected when the pattern matches the range variable and any case guard evaluates to true. + +Switch expression also support [type patterns][pattern-matching] and recursive matching. + +#### Throw expressions + +[`throw` expressions][throw-expressions] are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions. + +```csharp +string trimmed = str == null ? throw new ArgumentException() : str.Trim(); +``` + +If `str` is `null` in the above code an exception is thrown. + +#### Reference + +- [Expressions][expressions]: explains what expressions are. +- [Expression-bodied members][expression-bodied-members]: what expression-bodied members are and how to define them. + +[expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expressions +[expression-bodied-members]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members +[ternary-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator +[switch-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression +[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#patterns-and-case-guards +[throw-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression diff --git a/exercises/concept/expression-bodied-members/.docs/hints.md b/exercises/concept/expression-bodied-members/.docs/hints.md new file mode 100644 index 0000000000..aff0a17b44 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.docs/hints.md @@ -0,0 +1,11 @@ +## General + +- Expression bodied members are discussed [here][expression-bodied-members]. +- Ternary operators are discussed [here][ternary-operators]. +- Switch expressions are discussed [here][switch-expressions]. +- Throw expressions are covered [here][throw-expressions]. + +[expression-bodied-members]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members +[ternary-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator +[switch-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression +[throw-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression diff --git a/exercises/concept/expression-bodied-members/.docs/instructions.md b/exercises/concept/expression-bodied-members/.docs/instructions.md new file mode 100644 index 0000000000..41b75cee07 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.docs/instructions.md @@ -0,0 +1,9 @@ +You have been asked to improve some legacy code relating to a weather station. + +The weather station accepts readings, and outputs some indicators such as temperature and pressure. + +## 1. Improve the conciseness and readability of appropriate methods + +Refactor any appropriate methods of the `WeatherStation` class using expression bodied members. Use ternary operations and switch expressions where appropriate to improve expressiveness and potentially reduce errors. + +Ensure that all tests continue to pass. diff --git a/exercises/concept/expression-bodied-members/.docs/introduction.md b/exercises/concept/expression-bodied-members/.docs/introduction.md new file mode 100644 index 0000000000..425ebe588a --- /dev/null +++ b/exercises/concept/expression-bodied-members/.docs/introduction.md @@ -0,0 +1,47 @@ +Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements. + +Methods and read-only properties are amongst the members that can be defined with expression bodies. + +```csharp +public int Times3(int input) => input * 3; + +public int Interesting => 1729; +``` + +#### Ternary operators + +Ternary operators allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone. + +The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`). + +```csharp +int a = 3, b = 4; +int max = a > b ? a : b; +// => 4 +``` + +`throw` expressions are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions. + +```csharp +string trimmed = str == null ? throw new ArgumentException() : str.Trim(); +``` + +#### Switch expressions + +A switch expression can match a value to one case in a set of patterns and return the associated value or take the associated action. The association is denoted by the `=>` symbol. In addition, each pattern can have an optional case guard introduced with the `when` keyword. The case guard expression must evaluate to true for that "arm" of the switch to be selected. The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found. + +```csharp +double xx = 42d; + +string interesting = xx switch +{ + 0 => "I suppose zero is interesting", + 3.14 when DateTime.Now.Day == 14 && DateTime.Now.Month == 3 => "Mmm pie!", + 3.14 => "π", + 42 => "a bit of a cliché", + 1729 => "only if you are a pure mathematician", + _ => "not interesting" +}; + +// => interesting == "a bit of a cliché" +``` diff --git a/exercises/concept/expression-bodied-members/.meta/Example.cs b/exercises/concept/expression-bodied-members/.meta/Example.cs new file mode 100644 index 0000000000..00795ea694 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.meta/Example.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; + +public class WeatherStation +{ + private Reading reading; + private List recordDates = new List(); + private List temperatures = new List(); + + public int AcceptReading(Reading reading) + { + this.reading = reading; + recordDates.Add(DateTime.Now); + temperatures.Add(reading.Temperature); + return recordDates.Count; + } + + public void ClearAll() + { + this.reading = new Reading(); + recordDates.Clear(); + temperatures.Clear(); + } + + public decimal LatestTemperature => reading.Temperature; + + public decimal LatestPressure => reading.Pressure; + + public decimal LatestRainfall => reading.Rainfall; + + public bool HasHistory => recordDates.Count > 1; + + public Outlook ShortTermOutlook + => reading.Equals(new Reading()) ? throw new ArgumentException() + : reading.Pressure < 10m && reading.Temperature < 30m ? Outlook.Cool + : reading.Temperature > 50 ? Outlook.Good + : Outlook.Warm; + + public Outlook LongTermOutlook + => reading.WindDirection switch + { + WindDirection.Southerly => Outlook.Good, + WindDirection.Northerly => Outlook.Cool, + WindDirection.Easterly when reading.Temperature <= 20 => Outlook.Warm, + WindDirection.Easterly => Outlook.Good, + WindDirection.Westerly => Outlook.Rainy, + _ => throw new ArgumentException() + }; + + public State RunSelfTest() => reading.Equals(new Reading()) ? State.Bad : State.Good; +} + +/*** Please do not modify this struct ***/ +public struct Reading +{ + public decimal Temperature { get; } + public decimal Pressure { get; } + public decimal Rainfall { get; } + public WindDirection WindDirection { get; } + + public Reading(decimal temperature, decimal pressure, + decimal rainfall, WindDirection windDirection) + { + Temperature = temperature; + Pressure = pressure; + Rainfall = rainfall; + WindDirection = windDirection; + } +} + +/*** Please do not modify this enum ***/ +public enum State +{ + Good, + Bad +} + +/*** Please do not modify this enum ***/ +public enum Outlook +{ + Cool, + Rainy, + Warm, + Good +} + +/*** Please do not modify this enum ***/ +public enum WindDirection +{ + Unknown = 0, // default + Northerly, + Easterly, + Southerly, + Westerly +} diff --git a/exercises/concept/expression-bodied-members/.meta/config.json b/exercises/concept/expression-bodied-members/.meta/config.json new file mode 100644 index 0000000000..9212d455d1 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/expression-bodied-members/.meta/design.md b/exercises/concept/expression-bodied-members/.meta/design.md new file mode 100644 index 0000000000..9749e1def9 --- /dev/null +++ b/exercises/concept/expression-bodied-members/.meta/design.md @@ -0,0 +1,31 @@ +## Learning objectives + +- Know the difference between statements and expressions. +- Know how to define expression bodied members. +- Know how to use ternary expressions - using the `?:` operator. +- Know how to use `throw` expressions. +- know how to pattern match on values with `switch`. +- know how to use `when` guards with `switch`. + +## Out of scope + +- Performance difference between statements and expressions. +- Pattern matching on types with `switch`. + +## Concepts + +- `expression-bodied-members`: know the difference between statements and expressions; know how to define expression bodied members. +- `conditionals-ternary`: know how and when to use the ternary operator. +- `throw-expressions`: know how to use a `throw` expression. +- `switch-expressions`: know how to pattern match on values; know how to use `when` guards + +## Prerequisites + +- `classes`: know how to define methods on classes. +- `constructors`: know how to define constructors. +- `properties`: know how to define properties. +- `booleans` +- `conditionals-if` +- `exceptions` +- `switch statements`: background for `switch expressions`. +- `datetimes`: `DateTiime.Now` is used in example code. diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs b/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs new file mode 100644 index 0000000000..adb19dab23 --- /dev/null +++ b/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using Xunit.Sdk; + +public class WeatherStation +{ + private Reading reading; + private List recordDates = new List(); + private List temperatures = new List(); + + public void AcceptReading(Reading reading) + { + this.reading = reading; + recordDates.Add(DateTime.Now); + temperatures.Add(reading.Temperature); + } + + public void ClearAll() + { + this.reading = new Reading(); + recordDates.Clear(); + temperatures.Clear(); + } + + public decimal LatestTemperature + { + get + { + return reading.Temperature; + } + } + + public decimal LatestPressure + { + get + { + return reading.Pressure; + } + } + + public decimal LatestRainfall + { + get + { + return reading.Rainfall; + } + } + + public bool HasHistory + { + get + { + if (recordDates.Count > 1) + { + return true; + } + else + { + return false; + } + } + } + + public Outlook ShortTermOutlook + { + get + { + if (reading.Equals(new Reading())) + { + throw new ArgumentException(); + } + else + { + if (reading.Pressure < 10m && reading.Temperature < 30m) + { + return Outlook.Cool; + } + else if (reading.Temperature > 50) + { + return Outlook.Good; + } + else + { + return Outlook.Warm; + } + } + } + } + + public Outlook LongTermOutlook + { + get + { + if (reading.WindDirection == WindDirection.Southerly + || reading.WindDirection == WindDirection.Easterly + && reading.Temperature > 20) + { + return Outlook.Good; + } + if (reading.WindDirection == WindDirection.Northerly) + { + return Outlook.Cool; + } + if (reading.WindDirection == WindDirection.Easterly + && reading.Temperature <= 20) + { + return Outlook.Warm; + } + if (reading.WindDirection == WindDirection.Westerly) + { + return Outlook.Rainy; + } + throw new ArgumentException(); + } + } + + public State RunSelfTest() + { + if (reading.Equals(new Reading())) + { + return State.Bad; + } + else + { + return State.Good; + } + } +} + +/*** Please do not modify this struct ***/ +public struct Reading +{ + public decimal Temperature { get; } + public decimal Pressure { get; } + public decimal Rainfall { get; } + public WindDirection WindDirection { get; } + + public Reading(decimal temperature, decimal pressure, + decimal rainfall, WindDirection windDirection) + { + Temperature = temperature; + Pressure = pressure; + Rainfall = rainfall; + WindDirection = windDirection; + } +} + +/*** Please do not modify this enum ***/ +public enum State +{ + Good, + Bad +} + +/*** Please do not modify this enum ***/ +public enum Outlook +{ + Cool, + Rainy, + Warm, + Good +} + +/*** Please do not modify this enum ***/ +public enum WindDirection +{ + Unknown = 0, // default + Northerly, + Easterly, + Southerly, + Westerly +} diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj b/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs b/exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs new file mode 100644 index 0000000000..cf34c437a8 --- /dev/null +++ b/exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs @@ -0,0 +1,137 @@ +using System; +using Xunit; + +public class ExpressionBodiedMembersTests +{ + [Fact] + public void GetReading() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); + decimal[] expected = {20, 25, 0.01m}; + decimal[] actual = {ws.LatestTemperature, ws.LatestPressure, ws.LatestRainfall}; + Assert.Equal(expected, actual); + } + + [Fact] + public void HasHistory_no() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); + Assert.False(ws.HasHistory); + } + + [Fact] + public void HasHistory_yes() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); + ws.AcceptReading(new Reading(21m, 25m, 0.00m, WindDirection.Unknown)); + Assert.True(ws.HasHistory); + } + + [Fact] + public void ClearAll() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); + ws.AcceptReading(new Reading(21m, 25m, 0.00m, WindDirection.Unknown)); + ws.ClearAll(); + object[] expected = {false, 0m}; + object[] actual = {ws.HasHistory, ws.LatestTemperature}; + Assert.Equal(expected, actual); + } + + [Fact] + public void ShortTermOutlook_exception() + { + var ws = new WeatherStation(); + Assert.Throws(() => ws.ShortTermOutlook); + } + + [Fact] + public void ShortTermOutlook_cool() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(7m, 7m, 0m, WindDirection.Unknown)); + Assert.Equal(Outlook.Cool, ws.ShortTermOutlook); + } + + [Fact] + public void ShortTermOutlook_good() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(55m, 7m, 0m, WindDirection.Unknown)); + Assert.Equal(Outlook.Good, ws.ShortTermOutlook); + } + + [Fact] + public void ShortTermOutlook_warm() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(40m, 7m, 0m, WindDirection.Unknown)); + Assert.Equal(Outlook.Warm, ws.ShortTermOutlook); + } + + [Fact] + public void RunSelfTest_good() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(40m, 7m, 0m, WindDirection.Unknown)); + Assert.Equal(State.Good, ws.RunSelfTest()); + } + + [Fact] + public void RunSelfTest_bad() + { + var ws = new WeatherStation(); + Assert.Equal(State.Bad, ws.RunSelfTest()); + } + + [Fact] + public void LongTermOutlook_exception() + { + var ws = new WeatherStation(); + Assert.Throws(() => ws.LongTermOutlook); + } + + [Fact] + public void LongTermOutlook_cool() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(7m, 7m, 0m, WindDirection.Northerly)); + Assert.Equal(Outlook.Cool, ws.LongTermOutlook); + } + + [Fact] + public void LongTermOutlook_good() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(21m, 7m, 0m, WindDirection.Easterly)); + Assert.Equal(Outlook.Good, ws.LongTermOutlook); + } + + [Fact] + public void LongTermOutlook_good2() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(7m, 7m, 0m, WindDirection.Southerly)); + Assert.Equal(Outlook.Good, ws.LongTermOutlook); + } + + [Fact] + public void LongTermOutlook_warm() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(7m, 7m, 0m, WindDirection.Easterly)); + Assert.Equal(Outlook.Warm, ws.LongTermOutlook); + } + + [Fact] + public void LongTermOutlook_rainy() + { + var ws = new WeatherStation(); + ws.AcceptReading(new Reading(21m, 7m, 0m, WindDirection.Westerly)); + Assert.Equal(Outlook.Rainy, ws.LongTermOutlook); + } +} From 5bf3daf7c922254501261ac6f0c3603bb6280218 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 6 Aug 2020 09:29:58 -0400 Subject: [PATCH 189/327] constants new exercise * tuples first shot * tuples aligned with latest document formatting * tweaked design doc * tuples after.md * tuples introduction.md * tuples tweaks to introduction.md * tuples tweak to introduction.md * tuples fixed typos in instructions.md * added exercise template * tuples tweaks * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples after review * tuples after review * Apply suggestions from code review Co-authored-by: Erik Schierboom * tuples late review * tuples missed reveiew point * tuples missed reveiew point * Apply suggestions from code review Co-authored-by: Erik Schierboom * concept-doc updated equality, tuples, randomness * master - put aa-template in its own branch * structs - after grabbing structs directory from origin * master dropped files that should not have been in this branch. * constants initial commit * constants draft PR * constants decapitalisd exercise name * constants code style * constants - typos * constants - proofing * Update languages/exercises/concept/constants/.docs/introduction.md Co-authored-by: Erik Schierboom * constants review points * constants review points * constants review points * constants proofing * constants proofing * constants added config.json Co-authored-by: Erik Schierboom --- exercises/concept/constants/.docs/after.md | 82 +++++++++++++++++++ exercises/concept/constants/.docs/hints.md | 30 +++++++ .../concept/constants/.docs/instructions.md | 21 +++++ .../concept/constants/.docs/introduction.md | 43 ++++++++++ exercises/concept/constants/.meta/Example.cs | 54 ++++++++++++ exercises/concept/constants/.meta/config.json | 14 ++++ exercises/concept/constants/.meta/design.md | 30 +++++++ exercises/concept/constants/Constants.cs | 54 ++++++++++++ exercises/concept/constants/Constants.csproj | 13 +++ exercises/concept/constants/ConstantsTests.cs | 24 ++++++ 10 files changed, 365 insertions(+) create mode 100644 exercises/concept/constants/.docs/after.md create mode 100644 exercises/concept/constants/.docs/hints.md create mode 100644 exercises/concept/constants/.docs/instructions.md create mode 100644 exercises/concept/constants/.docs/introduction.md create mode 100644 exercises/concept/constants/.meta/Example.cs create mode 100644 exercises/concept/constants/.meta/config.json create mode 100644 exercises/concept/constants/.meta/design.md create mode 100644 exercises/concept/constants/Constants.cs create mode 100644 exercises/concept/constants/Constants.csproj create mode 100644 exercises/concept/constants/ConstantsTests.cs diff --git a/exercises/concept/constants/.docs/after.md b/exercises/concept/constants/.docs/after.md new file mode 100644 index 0000000000..d1aec92b5a --- /dev/null +++ b/exercises/concept/constants/.docs/after.md @@ -0,0 +1,82 @@ +#### const + +The [`const`][constants] modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program. + +```csharp +private const int num = 1729; +public const string title = "Grand" + " Master"; +``` + +The compiler will guide you as to what expressions can be evaluated at compile-time. Simple arithmetic operations are allowed as is string concatenation. This excludes any evaluation that would require use of the heap or stack so all method calls and references to non-primitive types are not available. + +There is some discussion on the web about the performance advantages of `const` over variables. In the case of a comparison with instance non-const fields there could be a noticeable saving in memory but compared to static variables that is decidedly trivial. Any consideration of CPU performance is likely to be seen by your colleagues as [premature optimization][premature-optimization]. + +A more compelling reason to use `const` is that it enhances a maintainer's ability to reason about the code. Glimpsing that a field is marked as `const` or `readonly` or that a property has no setter allows the maintainer largely to dismiss it from their analysis. It is unlikely to be the seat of bugs. It is unlikely to pose difficulties in a refactoring exercise. This [Stack Overflow comment][so-consts] addresses this. + +The `const` modifier can also be applied to values within methods: + +```csharp +public double Area(double r) +{ + const double π = 3.142; + return System.Math.Pow((π * r), 2); +} +``` + +Identifying a value with `const` in this way can be useful if it is used multiple times in the method or you want to draw attention to its meaning. There is no performance gain over using literals inline. + +#### readonly + +The [`readonly`][readonly-fields] modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor). + +```csharp +private readonly int num; +private readonly System.Random rand = new System.Random(); + +public MyClass(int num) +{ + this.num = num; +} +``` + +Use of the `readonly` modifier is encouraged for the same reasons that apply to `const`. The practice of constraining fields in this way helps maintainers reason about the code. + +Note that adding the `readonly` modifier to a field prevents only the value of the field from being changed. In the case of aggregate types it does not protect the fields or properties of that type. In particular, it does not protect the contents of arrays. + +```csharp +private readonly IList list = new List(); + +public void Foo() +{ + list = new List(); // does not compile + + list.Add("new stuff"); // succeeds at runtime +} +``` + +To ensure that all members of a reference type are protected the fields can be made `readonly` and automatic properties can be defined without a `set` accessor. + +You should examine [read-only collections][readonly-collections] in the Base Class Library. + +For arrays the closest you can get to a read-only version is the [`Array.AsReadOnly()][as-read-only] method. + +#### Defensive Copying + +Reflecting back on the coding exercise, imagine you have a code-base of several hundred thousand lines. You are passed the dictionary of developers into some method you are developing. Perhaps you have been tasked with printing out details of privileged developers. You decide to blank out the eye color in the dictionary to protect the developers' privacy. Unless a [deep copy][so-deep-copy] of the dictionary was made in the `Authenticator.GetDevelopers()` method, or, even better, it was wrapped in a read-only collection then you will have just trashed the authenticator. + +This follows the principle of [defensive copying][defensive-copying]. You can make sure your formal API is not circumvented by avoiding exposure to callers of internal writeable state. + +#### Reference + +- [Readonly fields][readonly-fields]: how to define a readonly field. +- [Constants][constants]: how to define constants. + +[readonly-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example +[constants]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants +[so-consts]: https://stackoverflow.com/a/5834473/96167 +[premature-optimization]: https://wiki.c2.com/?PrematureOptimization +[so-deep-copy]: https://stackoverflow.com/questions/78536/deep-cloning-objects +[defensive-copying]: https://www.informit.com/articles/article.aspx?p=31551&seqNum=2 +[as-read-only]: https://docs.microsoft.com/en-us/dotnet/api/system.array.asreadonly?view=netcore-3.1 +[readonly-collections]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1?view=netcore-3.1 +[so-deep-copy]: https://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy#:~:text=A%20deep%20copy%20occurs%20when,objects%20to%20which%20it%20refers.&text=Shallow%20copy%20is%20a%20bit,values%20in%20the%20original%20object. diff --git a/exercises/concept/constants/.docs/hints.md b/exercises/concept/constants/.docs/hints.md new file mode 100644 index 0000000000..72d763a713 --- /dev/null +++ b/exercises/concept/constants/.docs/hints.md @@ -0,0 +1,30 @@ +## General + +- [Readonly fields][readonly-fields]: how to define a readonly field. +- [Constants][constants]: how to define constants. + +## 1. Set appropriate fields and properties to const + +- Constants in C# are discussed [here][constants]. + +## 2. Set appropriate fields to readonly + +- Read-only fields are discussed [here][readonly-fields]. + +## 3. Remove set accessor or make it private for any appropriate field + +- This [article][properties] discusses C# properties. + +## 4. Ensure that the admin cannot be tampered with + +- See [this][defensive-copying] discussion on the pattern and purpose of defensive copying. + +## 5. Ensure that the developers cannot be tampered with + +- Read-only dictionaries are discussed [here][readonly-dictionaries]. + +[readonly-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example +[constants]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants +[properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties +[defensive-copying]: https://www.informit.com/articles/article.aspx?p=31551&seqNum=2 +[readonly-dictionaries]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlydictionary-2?view=netcore-3.1 diff --git a/exercises/concept/constants/.docs/instructions.md b/exercises/concept/constants/.docs/instructions.md new file mode 100644 index 0000000000..2d5d4d2592 --- /dev/null +++ b/exercises/concept/constants/.docs/instructions.md @@ -0,0 +1,21 @@ +The authentication system that you last saw in (TODO cross-ref-tba) is in need of some attention. You have been tasked with cleaning up the code. Such a cleanup project will not only make life easy for future maintainers but will expose and fix some security vulnerabilities. + +## 1. Set appropriate fields and properties to const + +This is a refactoring task. Add the `const` modifier to any members of `Authenticator` or `Identity` that you think appropriate. + +## 2. Set appropriate fields to readonly + +This is a refactoring task. Add the `readonly` modifier to any fields of the `Authenticator` class or the `Identity` struct that you think appropriate. + +## 3. Ensure that the class cannot be changed once it has been created + +Remove the `set` accessor or make it `private` for any appropriate property on the `Authenticator` class or `Identity` struct. + +## 4. Ensure that the admin cannot be tampered with + +At present the admin identity field is returned by a call to `Admin`. This is not ideal as the caller can modify the field. Find a way to prevent the caller modifying the details of admin on the `Authenticator` object. + +## 5. Ensure that the developers cannot be tampered with + +At present the dictionary containing the hard coded privileged developer identities is returned by a call to `GetDevelopers()`. This is not ideal as the caller can modify the dictionary. Find a way to prevent the caller modifying the details of admin on the `Authenticator` object. diff --git a/exercises/concept/constants/.docs/introduction.md b/exercises/concept/constants/.docs/introduction.md new file mode 100644 index 0000000000..9f526174a9 --- /dev/null +++ b/exercises/concept/constants/.docs/introduction.md @@ -0,0 +1,43 @@ +The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program. + +```csharp +private const int num = 1729; +public const string title = "Grand" + " Master"; +``` + +The `readonly` modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor). + +```csharp +private readonly int num; +private readonly System.Random rand = new System.Random(); + +public MyClass(int num) +{ + this.num = num; +} +``` + +#### Read-only collections + +Although the `readonly` modifier prevents the value or reference in a field from being overwritten, the modifier provides no protection for the members of a reference type. + +```csharp +readonly List ints = new List(); + +void Foo() +{ + ints.Add(1); // ok + ints = new List(); // fails to compile +} +``` + +To ensure that all members of a reference type are protected the fields can be made `readonly` and automatic properties can be defined without a `set` accessor. + +The Base Class Library (BCL) provides some readonly versions of collections where there is a requirement to stop members of a collections being updated. These come in the form of wrappers: + +- `ReadOnlyDictionary` exposes a `Dictionary` as read-only. +- `ReadOnlyCollection` exposes a `List` as read-only. + +#### Defensive copying + +In security sensitive situations (or even simply on a large code-base where developers have different priorities and agendas) you should avoid allowing a class's public API to be circumvented by accepting and storing a method's mutable parameters or by exposing a mutable member of a class through a return value or as an `out` parameter. diff --git a/exercises/concept/constants/.meta/Example.cs b/exercises/concept/constants/.meta/Example.cs new file mode 100644 index 0000000000..ba5fb61178 --- /dev/null +++ b/exercises/concept/constants/.meta/Example.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using System.Collections.ObjectModel; + +public class Authenticator +{ + private class EyeColor + { + public const string Blue = "blue"; + public const string Green = "green"; + public const string Brown = "brown"; + public const string Hazel = "hazel"; + public const string Brey = "grey"; + } + + private readonly Identity admin; + + public Authenticator(Identity admin) + { + this.admin = admin; + } + + private readonly IDictionary developers + = new Dictionary + { + ["Bertrand"] = new Identity + { + Email = "bert@ex.ism", + EyeColor = "blue" + }, + + ["Anders"] = new Identity + { + Email = "anders@ex.ism", + EyeColor = "brown" + } + }; + + public Identity Admin + { + get { return new Identity {Email = admin.Email, EyeColor = admin.EyeColor}; } + } + + public IReadOnlyDictionary GetDevelopers() + { + return new ReadOnlyDictionary(developers); + } +} + +public struct Identity +{ + public string Email { get; set; } + + public string EyeColor { get; set; } +} diff --git a/exercises/concept/constants/.meta/config.json b/exercises/concept/constants/.meta/config.json new file mode 100644 index 0000000000..9212d455d1 --- /dev/null +++ b/exercises/concept/constants/.meta/config.json @@ -0,0 +1,14 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ] +} diff --git a/exercises/concept/constants/.meta/design.md b/exercises/concept/constants/.meta/design.md new file mode 100644 index 0000000000..1249ec00b6 --- /dev/null +++ b/exercises/concept/constants/.meta/design.md @@ -0,0 +1,30 @@ +## Learning objectives + +- Know how to define `const` values. +- Know how to define `readonly` values. +- Know when to use `const` or `readonly`. +- know how to make a collection read-only +- understand the difference between the role of the `readonly` modifier and the use of read-only collections +- know how and when to use defensive copying + +## Out of scope + +- `readonly` structs +- `readonly` properties +- `ref readonly` + +## Concepts + +- `constants`: know how to define `const` values; know how to define `readonly` modifier know when to use `const` or `readonly`. +- `readonly-collections`: know how to make a collection read-only; understand the difference between the role of the `readonly` modifier and the use of readonly collections +- `defensive-copying`: know how and when to use defensive copying + +## Prerequisites + +- `classes`: know how to define fields. +- `basics`: know how to define variables. +- `object-initializers`: part of the provided code +- `arrays`: referred to in _after.md_ +- `properties`: understand how accessors are independent of each other +- `dictionaries`: understand the syntax and semantics of dictionaries (incl. in code) +- `nested-types`: understand the syntax of semantics nested types (incl. in code) diff --git a/exercises/concept/constants/Constants.cs b/exercises/concept/constants/Constants.cs new file mode 100644 index 0000000000..fa35c435e3 --- /dev/null +++ b/exercises/concept/constants/Constants.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; + +public class Authenticator +{ + private class EyeColor + { + public string Blue = "blue"; + public string Green = "green"; + public string Brown = "brown"; + public string Hazel = "hazel"; + public string Brey = "grey"; + } + + public Authenticator(Identity admin) + { + this.admin = admin; + } + + private Identity admin; + + private IDictionary developers + = new Dictionary + { + ["Bertrand"] = new Identity + { + Email = "bert@ex.ism", + EyeColor = "blue" + }, + + ["Anders"] = new Identity + { + Email = "anders@ex.ism", + EyeColor = "brown" + } + }; + + public Identity Admin + { + get { return admin; } + set { admin = value; } + } + + public IDictionary GetDevelopers() + { + return developers; + } +} + +public struct Identity +{ + public string Email { get; set; } + + public string EyeColor { get; set; } +} diff --git a/exercises/concept/constants/Constants.csproj b/exercises/concept/constants/Constants.csproj new file mode 100644 index 0000000000..e7a827a208 --- /dev/null +++ b/exercises/concept/constants/Constants.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + diff --git a/exercises/concept/constants/ConstantsTests.cs b/exercises/concept/constants/ConstantsTests.cs new file mode 100644 index 0000000000..9c9346888d --- /dev/null +++ b/exercises/concept/constants/ConstantsTests.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using Xunit; + +public class ObjectInitializationTests +{ + [Fact] + public void GetAdmin() + { + var admin = new Identity {EyeColor = "green", Email = "admin@ex.ism"}; + var authenticator = new Authenticator(admin); + Assert.Equal(admin, authenticator.Admin); + } + + [Fact] + public void GetDevelopers() + { + var authenticator = new Authenticator(new Identity {EyeColor = "green", Email = "admin@ex.ism"}); + var devs = authenticator.GetDevelopers() as IDictionary; + bool?[] actual = {devs != null, devs?.Count == 2, devs?["Anders"].EyeColor == "brown"}; + bool?[] expected = {true, true, true}; + Assert.Equal(expected, actual); + } +} From 5b9a697a3eaadd39db54b6007a9c42a5d80e5884 Mon Sep 17 00:00:00 2001 From: archrisV Date: Thu, 6 Aug 2020 17:08:26 +0200 Subject: [PATCH 190/327] Added Exceptions exercise * added structure for csharp\Exceptions exercise initial commit for the csharp\Exceptions exercise * Update introduction.md * Renamed class name in Expectations.cs * Initial instructions and Example.cs * Prepared solution, tests and starting file * Example.cs fixed * Fixed Example.cs * Initial instructions.md draft * Config.json formatted with prettier * Prettier formating for instructions/introduction * Exceptions.cs modified * Implemented suggestion from ErikSchierboom * Updates to Exceptions * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.docs/introduction.md Co-authored-by: Erik Schierboom * Update languages/exercises/concept/exceptions/.meta/design.md Co-authored-by: Erik Schierboom * Addressed concerns and modified instructions.md * Prettier ran Co-authored-by: Erik Schierboom --- exercises/concept/exceptions/.docs/after.md | 9 +++ exercises/concept/exceptions/.docs/hints.md | 0 .../concept/exceptions/.docs/instructions.md | 41 ++++++++++ .../concept/exceptions/.docs/introduction.md | 44 ++++++++++ exercises/concept/exceptions/.meta/Example.cs | 62 ++++++++++++++ .../concept/exceptions/.meta/config.json | 8 ++ exercises/concept/exceptions/.meta/design.md | 51 ++++++++++++ exercises/concept/exceptions/Exceptions.cs | 30 +++++++ .../concept/exceptions/Exceptions.csproj | 13 +++ .../concept/exceptions/ExceptionsTests.cs | 80 +++++++++++++++++++ 10 files changed, 338 insertions(+) create mode 100644 exercises/concept/exceptions/.docs/after.md create mode 100644 exercises/concept/exceptions/.docs/hints.md create mode 100644 exercises/concept/exceptions/.docs/instructions.md create mode 100644 exercises/concept/exceptions/.docs/introduction.md create mode 100644 exercises/concept/exceptions/.meta/Example.cs create mode 100644 exercises/concept/exceptions/.meta/config.json create mode 100644 exercises/concept/exceptions/.meta/design.md create mode 100644 exercises/concept/exceptions/Exceptions.cs create mode 100644 exercises/concept/exceptions/Exceptions.csproj create mode 100644 exercises/concept/exceptions/ExceptionsTests.cs diff --git a/exercises/concept/exceptions/.docs/after.md b/exercises/concept/exceptions/.docs/after.md new file mode 100644 index 0000000000..2dd4d9e2d4 --- /dev/null +++ b/exercises/concept/exceptions/.docs/after.md @@ -0,0 +1,9 @@ +It is important to note that `exceptions` should be used in cases where something exceptional happens, an error that needs special handeling. It should not be used for control-flow of a program, as that is considered bad design, which often leads to bad performance and maintainability. + +Some of the more common exceptions include `IndexOutOfRangeException`, `ArgumentOutOfRangeException`, `NullReferenceException`, `StackOverflowException`, `ArgumentException`, `InvalidOperationException` and `DivideByZeroException`. + +Some of the cases when exceptions should be thrown include: + +- if the method cannot complete its defined functionality +- an inappropriate call to an object is made, based on the object state +- when an argument to a method causes an exception diff --git a/exercises/concept/exceptions/.docs/hints.md b/exercises/concept/exceptions/.docs/hints.md new file mode 100644 index 0000000000..e69de29bb2 diff --git a/exercises/concept/exceptions/.docs/instructions.md b/exercises/concept/exceptions/.docs/instructions.md new file mode 100644 index 0000000000..7f49b44564 --- /dev/null +++ b/exercises/concept/exceptions/.docs/instructions.md @@ -0,0 +1,41 @@ +In this exercise you will be building error handling for a simple integer calculator. To make matters simple, methods for calculating addition, multiplication and division are provided. + +The goal is to have a working calculator that returns a string with the following pattern: `16 + 51 = 67`, when provided with arguments `16`, `51` and `+`. + +```csharp +SimpleCalculator.Calculate(16, 51, "+"); // => returns "16 + 51 = 67" + +SimpleCalculator.Calculate(32, 6, "*"); // => returns "32 * 6 = 192" + +SimpleCalculator.Calculate(512, 4, "/"); // => returns "512 / 4 = 128" +``` + +## 1. Handle the code that may throw errors within the method Calculate + +The main method for implementation in this task will be the (_static_) `SimpleCalculator.Calculate()` method. It takes three arguments. The first two arguments are integer numbers on which an operation is going to be conducted. The third argument is of type string and for this excercise it is necessary to implement the following operations: + +- addition using the `+` string +- multiplication using the `-` string +- division using the `/` string + +## 2. Handle illegal operations + +Any other operation symbol should throw the `ArgumentOutOfRangeException` exception. If the operation argument is an empty string, then the method should throw the `ArgumentException` exception. When `null` is provided as an operation argument, then the method should throw the `ArgumentNullException` exception. This functionality and handling of operations should be contained in a `try` block. + +## 3. Handle the thrown Overflow exceptions + +When the `OverflowException` exception gets thrown, the code handling the exception should return the string of the following content: `The result of operation {operand1} {operation} {operand2} does not fit into integer type.`. + +```csharp +SimpleCalculator.Calculate(2_147_483_647, 2, "+"); // => returns "The result of operation 2147483647 + 2 does not fit into integer type." + +SimpleCalculator.Calculate(2_147_483_647, 2, "*"); // => returns "The result of operation 2147483647 * 2 does not fit into integer type." +``` + +## 4. Handle the thrown DivideByZero exceptions + +When a `DivideByZeroException` exception gets thrown, the handling code should return the string with the content `Division by zero is not allowed.`. Any other exception should not be handled by the `SimpleCalculator.Calculate()` method. + +```csharp +SimpleCalculator.Calculate(512, 0, "/"); // => returns "Division by zero is not allowed." +``` diff --git a/exercises/concept/exceptions/.docs/introduction.md b/exercises/concept/exceptions/.docs/introduction.md new file mode 100644 index 0000000000..20803e085a --- /dev/null +++ b/exercises/concept/exceptions/.docs/introduction.md @@ -0,0 +1,44 @@ +Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes. + +In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown. + +To signal that there should be an error in a certain part of the code, a new exception object needs to be created and then thrown,using the `throw` keyword: + +```csharp +using System; +static int Square(int number) +{ + if (number >= 46341) + { + throw new ArgumentException($"Argument {number} cannot be higher than 46340 as its' square doesn't fit into int type."); + } + return number * number; +} +``` + +When an exception gets thrown, the runtime has the task of finding a piece of code that is responsible for handling of that exception. If no appropriate handler is found, the runtime displays the unhandled exception message in addition to stoping the execution of the program. To create a handler for an exception, C# uses the try-catch statement, which consists of a `try` block and one or more `catch` clauses. The `try` block should contain and guard code that may result in the exception getting thrown. The `catch` clauses should contain code that handles the behaviour of the program after the error has occured. It is important to note that the order of exceptions matters after the `try` block, as when multiple exceptions are listed, the first matching `catch` clause is executed. + +```csharp +try +{ + if (number == -1) + { + throw new ArgumentException("The number cannot be equal to -1", "number"); + } + + if (number < 0) + { + throw new ArgumentOutOfRangeException("number", "The number cannot be negative"); + } + + // Process number ... +} +catch (ArgumentOutOfRangeException e) +{ + Console.WriteLine($"Number is out of range: {e.Message}"); +} +catch (ArgumentException) +{ + Console.WriteLine($"Invalid number"); +} +``` diff --git a/exercises/concept/exceptions/.meta/Example.cs b/exercises/concept/exceptions/.meta/Example.cs new file mode 100644 index 0000000000..a6d71ba388 --- /dev/null +++ b/exercises/concept/exceptions/.meta/Example.cs @@ -0,0 +1,62 @@ +using System; +static class SimpleCalculator +{ + public static string Calculate(int operand1, int operand2, string operation) + { + int result = 0; + try + { + switch(operation) + { + case "+": + result = Calculator.Addition(operand1, operand2); + break; + case "*": + result = Calculator.Multiplication(operand1, operand2); + break; + case "/": + result = Calculator.Division(operand1, operand2); + break; + case "": + throw new ArgumentException("Operation cannot be empty.", operation); + case null: + throw new ArgumentNullException(operation, "Operation cannot be null."); + default: + throw new ArgumentOutOfRangeException(operation, $"Operation {operation} does not exist"); + } + } + catch(OverflowException) + { + return $"The result of operation {operand1} {operation} {operand2} does not fit into integer type."; + } + catch(DivideByZeroException) + { + return "Division by zero is not allowed."; + } + + return $"{operand1} {operation} {operand2} = {result}"; + } +} + +public static class Calculator +{ + public static int Division(int operand1, int operand2) + { + return operand1 / operand2; + } + + public static int Multiplication(int operand1, int operand2) + { + checked + { + return operand1 * operand2; + } + } + public static int Addition(int operand1, int operand2) + { + checked + { + return operand1 + operand2; + } + } +} \ No newline at end of file diff --git a/exercises/concept/exceptions/.meta/config.json b/exercises/concept/exceptions/.meta/config.json new file mode 100644 index 0000000000..37e972ec01 --- /dev/null +++ b/exercises/concept/exceptions/.meta/config.json @@ -0,0 +1,8 @@ +{ + "contributors": [ + { + "github_username": "archrisV", + "exercism_username": "archrisV" + } + ] +} diff --git a/exercises/concept/exceptions/.meta/design.md b/exercises/concept/exceptions/.meta/design.md new file mode 100644 index 0000000000..540a0a9550 --- /dev/null +++ b/exercises/concept/exceptions/.meta/design.md @@ -0,0 +1,51 @@ +## Goal + +The goal of this exercise is to teach the student the Concept of Exceptions in C#. + +## Learning objectives + +- Know what exceptions are. +- Know when an exception should be thrown. +- Know how to throw (and rethrow) an exception. +- Know how to catch an exception. +- Know the most important built-in exceptions (`ArgumentException`, `InvalidOperationException`). + +## Out of scope + +- Exception filters. +- User-defined exceptions. +- try/finally blocks +- Memory and performance characteristics. + +## Concepts + +- `exceptions`: know what exceptions are; know when an exception should be thrown; know how to throw (and rethrow) an exception; know how to catch an exception; know the most important built-in exceptions (`ArgumentException`, `InvalidOperationException`). + +## Prequisites + +- `basics`: know how to do string interpolation and how to work with `int`s +- `inheritance`: know about class hierarchies +- `nullability`: know what `null` is +- `overflows`: know what an `OverflowException` is +- `switch-statements`: know how to write a `switch` statement + +## Resources to refer to + +### Hints + +- [Exceptions][exceptions]: basic introduction to exceptions. +- [Using exceptions][using-exceptions]: how to use exceptions. +- [Exception handling][exception-handling]: how to catch exceptions. +- [Creating and throwing exceptions][creating-and-throwing-exceptions]: how to create and throw exceptions. + +### After + +- [Exceptions][exceptions]: basic introduction to exceptions. +- [Using exceptions][using-exceptions]: how to use exceptions. +- [Exception handling][exception-handling]: how to catch exceptions. +- [Creating and throwing exceptions][creating-and-throwing-exceptions]: how to create and throw exceptions. + +[exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/ +[using-exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/using-exceptions +[exception-handling]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/exception-handling +[creating-and-throwing-exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions diff --git a/exercises/concept/exceptions/Exceptions.cs b/exercises/concept/exceptions/Exceptions.cs new file mode 100644 index 0000000000..25a614250b --- /dev/null +++ b/exercises/concept/exceptions/Exceptions.cs @@ -0,0 +1,30 @@ +using System; +static class SimpleCalculator +{ + public static string Calculate(int operand1, int operand2, string operation) + { + throw new NotImplementedException(); + } + +public static class Calculator +{ + public static int Division(int operand1, int operand2) + { + return operand1 / operand2; + } + + public static int Multiplication(int operand1, int operand2) + { + checked + { + return operand1 * operand2; + } + } + public static int Addition(int operand1, int operand2) + { + checked + { + return operand1 + operand2; + } + } +} \ No newline at end of file diff --git a/exercises/concept/exceptions/Exceptions.csproj b/exercises/concept/exceptions/Exceptions.csproj new file mode 100644 index 0000000000..0d9d54e3f8 --- /dev/null +++ b/exercises/concept/exceptions/Exceptions.csproj @@ -0,0 +1,13 @@ + + + + netcoreapp3.1 + + + + + + + + + \ No newline at end of file diff --git a/exercises/concept/exceptions/ExceptionsTests.cs b/exercises/concept/exceptions/ExceptionsTests.cs new file mode 100644 index 0000000000..d8a841729c --- /dev/null +++ b/exercises/concept/exceptions/ExceptionsTests.cs @@ -0,0 +1,80 @@ +using Xunit; +using System; +public class SimpleCalculatorTests +{ + //Addition tests + [Fact] + public void Addition_with_small_operands() + { + Assert.Equal("22 + 25 = 47", SimpleCalculator.Calculate(22, 25, "+")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Addition_with_large_operands() + { + Assert.Equal("378961 + 399635 = 778596", SimpleCalculator.Calculate(378_961, 399_635, "+")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Addition_that_overflows() + { + Assert.Equal("The result of operation 2147483647 + 5 does not fit into integer type.", SimpleCalculator.Calculate(Int32.MaxValue, 5, "+")); + } + + //Multiplication tests + [Fact(Skip = "Remove this Skip property to run this test")] + public void Multiplication_with_small_operands() + { + Assert.Equal("3 * 21 = 63", SimpleCalculator.Calculate(3, 21, "*")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Multiplication_with_large_operands() + { + Assert.Equal("72441 * 2048 = 148359168", SimpleCalculator.Calculate(72_441, 2_048, "*")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Multiplication_that_overflows() + { + Assert.Equal("The result of operation 50000 * 50000 does not fit into integer type.", SimpleCalculator.Calculate(50_000, 50_000, "*")); + } + + //Division tests + [Fact(Skip = "Remove this Skip property to run this test")] + public void Division_with_small_operands() + { + Assert.Equal("72 / 9 = 8", SimpleCalculator.Calculate(72, 9, "/")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Division_with_large_operands() + { + Assert.Equal("1338800 / 83675 = 16", SimpleCalculator.Calculate(1_338_800, 83_675, "/")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Calculate_throws_exception_for_division_with_0() + { + Assert.Equal("Division by zero is not allowed.", SimpleCalculator.Calculate(33, 0, "/")); + } + + // Invalid operator + [Fact(Skip = "Remove this Skip property to run this test")] + public void Calculate_throws_exception_for_non_valid_operations() + { + Assert.Throws(() => SimpleCalculator.Calculate(1, 2, "**")); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Calculate_throws_exception_for_null_as_operation() + { + Assert.Throws(() => SimpleCalculator.Calculate(1, 2, null)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Calculate_throws_exception_for_emtpy_string_as_operation() + { + Assert.Throws(() => SimpleCalculator.Calculate(1, 2, "")); + } +} \ No newline at end of file From 8b610c0b7236d6d3e3598e0a60bc97518ddf07d1 Mon Sep 17 00:00:00 2001 From: Bobby Towers Date: Fri, 7 Aug 2020 09:45:57 -0700 Subject: [PATCH 191/327] fix LogLevel method --- exercises/concept/strings/.meta/Example.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs index d140439625..a2e9bed840 100644 --- a/exercises/concept/strings/.meta/Example.cs +++ b/exercises/concept/strings/.meta/Example.cs @@ -7,7 +7,7 @@ public static string Message(string logLine) public static string LogLevel(string logLine) { - return logLine.Substring(1, logLine.IndexOf("]")).ToLower(); + return logLine.Substring(1, (logLine.IndexOf("]") - 1).ToLower(); } public static string Reformat(string logLine) From 9b41d4421fd3b22b524b856a83fcdcdd04e82505 Mon Sep 17 00:00:00 2001 From: Mike May Date: Sat, 15 Aug 2020 14:02:48 -0400 Subject: [PATCH 192/327] Update after.md typo --- exercises/concept/classes/.docs/after.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/classes/.docs/after.md b/exercises/concept/classes/.docs/after.md index acb0ef4333..d254869203 100644 --- a/exercises/concept/classes/.docs/after.md +++ b/exercises/concept/classes/.docs/after.md @@ -34,7 +34,7 @@ class Car } ``` -One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it wll be set to its type's [default value][default-values]. An instance's field values can be accessed and updated using dot-notation. +One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it will be set to its type's [default value][default-values]. An instance's field values can be accessed and updated using dot-notation. ```csharp class Car From e2bcb05e219ad1701bf4ef15d991a3c4b30370da Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 20 Aug 2020 09:02:45 +0100 Subject: [PATCH 193/327] new csharp exercise report action and revised reference/README.md * exercise-report new repo * exercise-report testing workflow 1 * exercise-report testing workflow 2 * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report testing workflow 2 * exercise-report dropped document link for design from json * exercise-report dropped document link for design from json * exercise-report dropped document link for design from json * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report fixed learning objectives * exercise-report introduced completion status * exercise-report finalized completion status * exercise-report finalized completion status * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report avoid dead link check for PR * exercise-report avoid dead link check for PR * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report for review * Update exercises.json * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report updated for latest exercises * exercise-report fixing broken links * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report report concepts with no learning objectives * exercise-report report concepts with no learning objectives * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report report concepts with no learning objectives * exercise-report added type-inference to `basics` design.md * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report added readme * exercise-report added readme * exercise-report removed deliberate typo * [CI] Format code * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report removed learning objectives from exercises.json * exercise-report removed learning objectives from exercises.json and refactored * [CI] Format code * java/classes proofing * java/classes proofing * java/classes proofing * exercise-report proofing * [CI] Format code * exercise-report struggling with prettier * exercise-report testing on github * exercise-report corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report testing corrections to exercises.json * [CI] Format code * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * exercise-report testing corrections to exercises.json * [Bot] Update exercise-report document Co-authored-by: github-actions[bot] * exercise-report addressed review points * exercise-report fixed wrongly named file Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] --- exercises/concept/basics/.meta/design.md | 1 + exercises/concept/structs/.meta/design.md | 2 +- reference/exercise-errors.json | 279 +++ reference/exercises.json | 2173 +++++++++++++++++++++ 4 files changed, 2454 insertions(+), 1 deletion(-) create mode 100644 reference/exercise-errors.json create mode 100644 reference/exercises.json diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index 1e1bbd478f..164a921bcc 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -31,6 +31,7 @@ ## Concepts - `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. +- `type-inference`: know how to use the keyword, `var`; know when it is appropriate to use type-inference ## Prerequisites diff --git a/exercises/concept/structs/.meta/design.md b/exercises/concept/structs/.meta/design.md index 1824ed74db..ca0f836330 100644 --- a/exercises/concept/structs/.meta/design.md +++ b/exercises/concept/structs/.meta/design.md @@ -19,7 +19,7 @@ This Concepts Exercise's Concepts are: -- `structs`: know what structs are; know how to define a `struct`; know how to add members to structs; know the differences between structs and classes. +- `structs`: know xx what structs are; know how to define a `struct`; know how to add members to structs; know the differences between structs and classes. ## Prerequisites diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json new file mode 100644 index 0000000000..d08e12f228 --- /dev/null +++ b/reference/exercise-errors.json @@ -0,0 +1,279 @@ +{ + "Errors": [ + { + "Severity": "error", + "Message": "nested-types: invalid format: - \u0060nested-types\u0060", + "Source": "design" + }, + { + "Severity": "error", + "Message": "regular-expressions: invalid format: - \u0060regular-expressions\u0060 as they are handled in C# and .NET.", + "Source": "design" + }, + { + "Severity": "error", + "Message": "resource-lifetime: invalid format: - \u0060resource-lifetime\u0060 as it is handled in C#.", + "Source": "design" + }, + { + "Severity": "error", + "Message": "Failed to find concept StringBuilder, from the chars design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept accessibility, from the namespaces design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept readonly-collections, from the constants design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept defensive-copying, from the constants design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept pattern-matching-constants, from the enums design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept while-loops, from the floating-point-numbers design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept exception-filtering, from the user-defined-exceptions design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept bit-manipulation, from the flag-enums design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept generic-types, from the lists design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept datetime, from the datetimes design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept throw-expressions, from the expression-bodied-members design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept switch-expressions, from the expression-bodied-members design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept optional-parameters, from the method-overloading design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept timezone, from the time design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "Failed to find concept overflows, from the overflow design.md, in exercises.json file", + "Source": "merge" + }, + { + "Severity": "error", + "Message": "The encapsulation concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The fields concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The objects concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The state concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The visibility concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The default-value concept has no learning objectives on the exercise report - update the design.md for the classes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The polymorphism concept has no learning objectives on the exercise report - update the design.md for the inheritance exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The return-values concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The mutation concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The functions concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The comments concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The scoping concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The variables concept has no learning objectives on the exercise report - update the design.md for the basics exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The null-coalescing concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The null-conditional concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The null-forgiving concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The nullable-values concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The math-operators concept has no learning objectives on the exercise report - update the design.md for the numbers exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The assignment concept has no learning objectives on the exercise report - update the design.md for the numbers exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The base-class-library concept has no learning objectives on the exercise report - update the design.md for the dictionaries exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The datetimes concept has no learning objectives on the exercise report - update the design.md for the datetimes exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The conditionals-while concept has no learning objectives on the exercise report - update the design.md for the floating-point-numbers exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The marker-interfaces concept has no learning objectives on the exercise report - update the design.md for the equality exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The out-parameters concept has no learning objectives on the exercise report - update the design.md for the parameters exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The optional-arguments concept has no learning objectives on the exercise report - update the design.md for the parameters exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The explicit-interfaces concept has no learning objectives on the exercise report - update the design.md for the interfaces exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The unsigned-integers concept has no learning objectives on the exercise report - update the design.md for the integral-numbers exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The collections concept has no learning objectives on the exercise report - update the design.md for the lists exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The imports concept has no learning objectives on the exercise report - update the design.md for the namespaces exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The formatting-types concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The interpolation concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The string-builder concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The regular-expressions concept has no learning objectives on the exercise report - update the design.md for the regular-expressions exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The resource-lifetime concept has no learning objectives on the exercise report - update the design.md for the resource-lifetime exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The overflow concept has no learning objectives on the exercise report - update the design.md for the overflow exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The nested-types concept has no learning objectives on the exercise report - update the design.md for the nested-types exercise", + "Source": "missingLearningObjective" + }, + { + "Severity": "error", + "Message": "The implicit-casting concept has no learning objectives on the exercise report - update the design.md for the casting exercise", + "Source": "missingLearningObjective" + } + ] +} diff --git a/reference/exercises.json b/reference/exercises.json new file mode 100644 index 0000000000..3bea6a5fd4 --- /dev/null +++ b/reference/exercises.json @@ -0,0 +1,2173 @@ +{ + "documentation": [ + "This file is the original source of the concept report in csharp/reference/README.md.", + "", + "You can:", + " Add new exercises, concepts and original concepts", + " Add or modify track neutral concepts", + " Change CompletionStatus on an existing exercise", + " Add or modify document link if the CompletionStatus is NewExerciseIssueRaised", + "You must:", + " Have a non-blank document link if and only if the CompletionStatus is NewExerciseIssueRaised" + ], + "exercises": [ + { + "slug": "classes", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "classes", + "track-neutral-concept": "reference/concepts/classes.md", + "original-concepts": [ + { + "name": "- [Classes][classes]", + "line-number": 11 + } + ] + }, + { + "name": "encapsulation", + "track-neutral-concept": "reference/concepts/encapsulation.md", + "original-concepts": [ + { + "name": "- [Encapsulation][encapsulation]", + "line-number": 13 + } + ] + }, + { + "name": "fields", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Fields", + "line-number": 14 + } + ] + }, + { + "name": "objects", + "track-neutral-concept": "reference/concepts/objects.md", + "original-concepts": [ + { + "name": "- [Objects][objects]", + "line-number": 32 + } + ] + }, + { + "name": "state", + "track-neutral-concept": "reference/concepts/state.md", + "original-concepts": [ + { + "name": "- [State][state]", + "line-number": 36 + } + ] + }, + { + "name": "visibility", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Visibility (\u0060public\u0060; \u0060private\u0060; etc.)", + "line-number": 123 + } + ] + }, + { + "name": "default-value", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Default values (a \u0060bool\u0060 being \u0060false\u0060 by default; etc.)", + "line-number": 133 + } + ] + } + ] + }, + { + "slug": "inheritance", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "inheritance", + "track-neutral-concept": "reference/concepts/inheritance.md", + "original-concepts": [ + { + "name": " [Inheritance][inheritance]", + "line-number": 16 + } + ] + }, + { + "name": "polymorphism", + "track-neutral-concept": "reference/concepts/polymorphism.md", + "original-concepts": [ + { + "name": "- [Polymorphism][polymorphism]", + "line-number": 34 + } + ] + } + ] + }, + { + "slug": "basics", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "basics", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " basics (including methods)", + "line-number": 20 + } + ] + }, + { + "name": "return-values", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Return values", + "line-number": 30 + } + ] + }, + { + "name": "mutation", + "track-neutral-concept": "reference/concepts/mutation.md", + "original-concepts": [ + { + "name": "- [Mutation][mutation]", + "line-number": 31 + } + ] + }, + { + "name": "functions", + "track-neutral-concept": "reference/types/function.md", + "original-concepts": [ + { + "name": "- [Functions][functions]", + "line-number": 46 + } + ] + }, + { + "name": "type-inference", + "track-neutral-concept": "reference/concepts/type_inference.md", + "original-concepts": [ + { + "name": "- [Type inference][type_inference]", + "line-number": 61 + } + ] + }, + { + "name": "comments", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Comments", + "line-number": 78 + } + ] + }, + { + "name": "scoping", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Scoping", + "line-number": 120 + } + ] + }, + { + "name": "variables", + "track-neutral-concept": "reference/concepts/variables.md", + "original-concepts": [ + { + "name": "- [Variables][variables]", + "line-number": 131 + } + ] + } + ] + }, + { + "slug": "constructors", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "constructors", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Constructors", + "line-number": 21 + } + ] + } + ] + }, + { + "slug": "method-overloading", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "method-overloading", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Method overloading", + "line-number": 28 + } + ] + } + ] + }, + { + "slug": "properties", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "properties", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Properties", + "line-number": 35 + } + ] + } + ] + }, + { + "slug": "nullability", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "nullability", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Null", + "line-number": 102 + } + ] + }, + { + "name": "null-coalescing", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Null-coalescing operator", + "line-number": 103 + } + ] + }, + { + "name": "null-conditional", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Null-conditional operator", + "line-number": 104 + } + ] + }, + { + "name": "null-forgiving", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Null-forgiving operator", + "line-number": 105 + } + ] + }, + { + "name": "nullable-values", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Nullable values", + "line-number": 106 + } + ] + } + ] + }, + { + "slug": "numbers", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "numbers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Numbers", + "line-number": 107 + } + ] + }, + { + "name": "conditionals", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Conditionals", + "line-number": 85 + } + ] + }, + { + "name": "math-operators", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Math operators", + "line-number": 110 + } + ] + }, + { + "name": "assignment", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Assignment", + "line-number": 132 + } + ] + }, + { + "name": "numbers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Numbers", + "line-number": 161 + } + ] + } + ] + }, + { + "slug": "booleans", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "booleans", + "track-neutral-concept": "reference/types/boolean.md", + "original-concepts": [ + { + "name": "- [Booleans][bool]", + "line-number": 138 + } + ] + }, + { + "name": "booleans", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Boolean logic", + "line-number": 86 + } + ] + } + ] + }, + { + "slug": "chars", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "chars", + "track-neutral-concept": "reference/types/char.md", + "original-concepts": [ + { + "name": "- [Characters][char]", + "line-number": 139 + } + ] + } + ] + }, + { + "slug": "arrays", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "arrays", + "track-neutral-concept": "reference/types/array.md", + "original-concepts": [ + { + "name": " - [Arrays][array]", + "line-number": 141 + } + ] + }, + { + "name": "for-loops", + "track-neutral-concept": "reference/concepts/enumeration.md", + "original-concepts": [ + { + "name": " - [Enumeration: for loop][enumeration]", + "line-number": 98 + } + ] + }, + { + "name": "foreach-loops", + "track-neutral-concept": "reference/concepts/enumeration.md", + "original-concepts": [ + { + "name": " - [Enumeration: foreach loop][enumeration]", + "line-number": 99 + } + ] + } + ] + }, + { + "slug": "dictionaries", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "dictionaries", + "track-neutral-concept": "reference/types/map.md", + "original-concepts": [ + { + "name": " - [Dictionaries][map]", + "line-number": 143 + } + ] + }, + { + "name": "base-class-library", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "Base Class Library", + "line-number": 174 + } + ] + } + ] + }, + { + "slug": "datetimes", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "datetimes", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Dates", + "line-number": 151 + } + ] + } + ] + }, + { + "slug": "enums", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "enums", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Enums", + "line-number": 155 + } + ] + } + ] + }, + { + "slug": "floating-point-numbers", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "floating-point-numbers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Floating point numbers", + "line-number": 162 + } + ] + }, + { + "name": "conditionals-while", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Conditionals: while", + "line-number": 89 + } + ] + } + ] + }, + { + "slug": "strings", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "strings", + "track-neutral-concept": "reference/types/string.md", + "original-concepts": [ + { + "name": "- [Strings][string]", + "line-number": 167 + } + ] + } + ] + }, + { + "slug": "flag-enums", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "flag-enums", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Flag Enums", + "line-number": 156 + } + ] + } + ] + }, + { + "slug": "user-defined-exceptions", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "user-defined-exceptions", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- User Defined Exceptions", + "line-number": 59 + } + ] + } + ] + }, + { + "slug": "equality", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "equality", + "track-neutral-concept": "reference/concepts/sameness.md", + "original-concepts": [ + { + "name": " - [Equality][equality] (\u0060Equals\u0060; \u0060GetHashCode\u0060)", + "line-number": 80 + } + ] + }, + { + "name": "marker-interfaces", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Marker interfaces", + "line-number": 19 + } + ] + }, + { + "name": "sets", + "track-neutral-concept": "reference/types/set.md", + "original-concepts": [ + { + "name": " - [Sets][set]", + "line-number": 149 + } + ] + } + ] + }, + { + "slug": "tuples", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "tuples", + "track-neutral-concept": "reference/types/tuple.md", + "original-concepts": [ + { + "name": "- [Tuples][tuple]", + "line-number": 170 + } + ] + } + ] + }, + { + "slug": "randomness", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "randomness", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Randomness", + "line-number": 111 + } + ] + } + ] + }, + { + "slug": "parameters", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "parameters", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Method arguments / parameters", + "line-number": 24 + } + ] + }, + { + "name": "named-arguments", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Named arguments", + "line-number": 25 + } + ] + }, + { + "name": "out-parameters", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Out parameters", + "line-number": 26 + } + ] + }, + { + "name": "optional-arguments", + "track-neutral-concept": "reference/concepts/default_arguments.md", + "original-concepts": [ + { + "name": " - [Optional arguments][optional_arguments]", + "line-number": 27 + } + ] + } + ] + }, + { + "slug": "switch-statements", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "switch-statements", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Conditionals: switch", + "line-number": 88 + } + ] + } + ] + }, + { + "slug": "object-initializers", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "object-initializers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Object initializers", + "line-number": 33 + } + ] + } + ] + }, + { + "slug": "resource-cleanup", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "resource-cleanup", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Resource cleanup (\u0060IDisposable\u0060)", + "line-number": 115 + } + ] + } + ] + }, + { + "slug": "time", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "time", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Time", + "line-number": 169 + } + ] + }, + { + "name": "cross-platform", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "cross-platform", + "line-number": 176 + } + ] + } + ] + }, + { + "slug": "interfaces", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "interfaces", + "track-neutral-concept": "reference/concepts/interfaces.md", + "original-concepts": [ + { + "name": "- [Interfaces][interfaces]", + "line-number": 17 + } + ] + }, + { + "name": "explicit-interfaces", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Explicit Interface Implementation", + "line-number": 18 + } + ] + } + ] + }, + { + "slug": "integral-numbers", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "integral-numbers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Signed integers", + "line-number": 163 + } + ] + }, + { + "name": "unsigned-integers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Unsigned integers", + "line-number": 164 + } + ] + } + ] + }, + { + "slug": "constants", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "constants", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Constants/readonly", + "line-number": 92 + } + ] + } + ] + }, + { + "slug": "exceptions", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "exceptions", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Exceptions", + "line-number": 100 + } + ] + } + ] + }, + { + "slug": "lists", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "lists", + "track-neutral-concept": "reference/types/list.md", + "original-concepts": [ + { + "name": " - [Lists][list]", + "line-number": 146 + } + ] + }, + { + "name": "collections", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Collections", + "line-number": 67 + } + ] + } + ] + }, + { + "slug": "structs", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "structs", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Structs", + "line-number": 38 + } + ] + } + ] + }, + { + "slug": "expression-bodied-members", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "expression-bodied-members", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Expression-bodied members", + "line-number": 44 + } + ] + }, + { + "name": "conditionals-ternary", + "track-neutral-concept": "reference/concepts/conditionals.md", + "original-concepts": [ + { + "name": " - [Conditionals: ternary][conditionals]", + "line-number": 91 + } + ] + } + ] + }, + { + "slug": "namespaces", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "namespaces", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Namespaces", + "line-number": 122 + } + ] + }, + { + "name": "imports", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Imports (usings)", + "line-number": 121 + } + ] + } + ] + }, + { + "slug": "string-formatting", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "string-formatting", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- String formatting", + "line-number": 126 + } + ] + }, + { + "name": "formatting-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Formatting types", + "line-number": 127 + } + ] + }, + { + "name": "interpolation", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Interpolation", + "line-number": 128 + } + ] + }, + { + "name": "string-builder", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - StringBuilder", + "line-number": 129 + } + ] + }, + { + "name": "verbatim-strings", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "verbatim strings", + "line-number": 172 + } + ] + } + ] + }, + { + "slug": "regular-expressions", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "regular-expressions", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Regular Expressions", + "line-number": 113 + } + ] + } + ] + }, + { + "slug": "resource-lifetime", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "resource-lifetime", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Resource lifetime", + "line-number": 116 + } + ] + } + ] + }, + { + "slug": "overflow", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "overflow", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Arithmetic overflow", + "line-number": 108 + } + ] + } + ] + }, + { + "slug": "nested-types", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "nested-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Nested types", + "line-number": 160 + } + ] + } + ] + }, + { + "slug": "casting", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "casting", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Explicit (casts)", + "line-number": 95 + } + ] + }, + { + "name": "implicit-casting", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Implicit", + "line-number": 96 + } + ] + } + ] + }, + { + "slug": "operator-overloading", + "level": "introductory", + "completion-status": "complete", + "document-link": "", + "concepts": [ + { + "name": "operator-overloading", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- operator overloading", + "line-number": 29 + } + ] + } + ] + }, + { + "slug": "delegates", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "delegates", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Delegates", + "line-number": 153 + } + ] + } + ] + }, + { + "slug": "attributes-advanced", + "level": "essential", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/1176", + "concepts": [ + { + "name": "attributes-advanced", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Attributes", + "line-number": 66 + } + ] + } + ] + }, + { + "slug": "reflection", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "reflection", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Reflection", + "line-number": 112 + } + ] + } + ] + }, + { + "slug": "events", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "events", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Events", + "line-number": 157 + } + ] + } + ] + }, + { + "slug": "streams", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "streams", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Streams", + "line-number": 166 + } + ] + } + ] + }, + { + "slug": "indexers", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "indexers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Indexers", + "line-number": 15 + } + ] + } + ] + }, + { + "slug": "recursion", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "recursion", + "track-neutral-concept": "reference/concepts/recursion.md", + "original-concepts": [ + { + "name": "- [Recursion][recursion]", + "line-number": 60 + } + ] + } + ] + }, + { + "slug": "pattern-matching-types", + "level": "essential", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/546", + "concepts": [ + { + "name": "pattern-matching-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Pattern Matching Types", + "line-number": 57 + } + ] + } + ] + }, + { + "slug": "pattern-matching-tuples", + "level": "essential", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/964", + "concepts": [ + { + "name": "pattern-matching-tuples", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Pattern Matching Tuples", + "line-number": 58 + } + ] + } + ] + }, + { + "slug": "tasks", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "tasks", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Tasks", + "line-number": 168 + } + ] + } + ] + }, + { + "slug": "async", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "async", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Asynchronous programming", + "line-number": 65 + } + ] + } + ] + }, + { + "slug": "thread-safety", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "thread-safety", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "thread safety", + "line-number": 173 + } + ] + } + ] + }, + { + "slug": "generics-advanced", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "generics-advanced", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Generics Constraints", + "line-number": 76 + } + ] + } + ] + }, + { + "slug": "covariance", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "covariance", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Covariance/Contravariance", + "line-number": 77 + } + ] + } + ] + }, + { + "slug": "contravariance", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "contravariance", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Concurrent collections", + "line-number": 83 + } + ] + } + ] + }, + { + "slug": "locks", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "locks", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Locks", + "line-number": 84 + } + ] + } + ] + }, + { + "slug": "serialization", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "serialization", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Serialization", + "line-number": 124 + } + ] + } + ] + }, + { + "slug": "extension-methods", + "level": "essential", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/1070", + "concepts": [ + { + "name": "extension-methods", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Extension methods", + "line-number": 23 + } + ] + } + ] + }, + { + "slug": "statics", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "statics", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Statics", + "line-number": 37 + } + ] + } + ] + }, + { + "slug": "lambdas", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "lambdas", + "track-neutral-concept": "reference/concepts/anonymous_functions.md", + "original-concepts": [ + { + "name": " - [Anonymous functions][anonymous_functions]", + "line-number": 47 + } + ] + } + ] + }, + { + "slug": "higher-order-functions", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "higher-order-functions", + "track-neutral-concept": "reference/concepts/higher_order_functions.md", + "original-concepts": [ + { + "name": " - [Higher-order functions][higher_order_functions]", + "line-number": 48 + } + ] + } + ] + }, + { + "slug": "linq", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "linq", + "track-neutral-concept": "reference/concepts/pipelines.md", + "original-concepts": [ + { + "name": "- [LINQ][linq]", + "line-number": 51 + } + ] + }, + { + "name": "collections-combining", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Collections: combining", + "line-number": 68 + } + ] + }, + { + "name": "collections-filtering", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Collections: filtering", + "line-number": 69 + } + ] + }, + { + "name": "collections-mapping", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Collections: mapping", + "line-number": 70 + } + ] + }, + { + "name": "collections-ordering", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Collections: ordering", + "line-number": 71 + } + ] + }, + { + "name": "collections-reducing", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Collections: reducing", + "line-number": 72 + } + ] + } + ] + }, + { + "slug": "anonymous-types", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "anonymous-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Anonymous types", + "line-number": 137 + } + ] + } + ] + }, + { + "slug": "enumerables", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "enumerables", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Enumerables", + "line-number": 144 + } + ] + } + ] + }, + { + "slug": "linq-advanced", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "linq-advanced", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Advanced (GroupBy; Join; Zip; Cast; GroupJoin; AsEnumerable)", + "line-number": 52 + } + ] + } + ] + }, + { + "slug": "linq-query-syntax", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "linq-query-syntax", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Query Syntax", + "line-number": 54 + } + ] + } + ] + }, + { + "slug": "linq-select-many", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "linq-select-many", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - SelectMany", + "line-number": 55 + } + ] + } + ] + }, + { + "slug": "yield", + "level": "essential", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "yield", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Iterators (yield)", + "line-number": 73 + } + ] + } + ] + }, + { + "slug": "immutable-collections", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "immutable-collections", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Immutable collections", + "line-number": 145 + } + ] + } + ] + }, + { + "slug": "by-ref", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "by-ref", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Resource passing (by reference/by value)", + "line-number": 117 + } + ] + } + ] + }, + { + "slug": "memory-allocation", + "level": "advanced", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/1018", + "concepts": [ + { + "name": "memory-allocation", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - [Resource allocation][memory_allocation]", + "line-number": 118 + } + ] + } + ] + }, + { + "slug": "queues", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "queues", + "track-neutral-concept": "reference/types/deque.md", + "original-concepts": [ + { + "name": " - [Queues][queue]", + "line-number": 147 + } + ] + } + ] + }, + { + "slug": "ranges", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "ranges", + "track-neutral-concept": "reference/types/range.md", + "original-concepts": [ + { + "name": " - [Ranges][range]", + "line-number": 148 + } + ] + } + ] + }, + { + "slug": "time-zones", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "time-zones", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Time zones", + "line-number": 152 + } + ] + } + ] + }, + { + "slug": "resource-pooling", + "level": "advanced", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/1146", + "concepts": [ + { + "name": "resource-pooling", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Resource Pooling", + "line-number": 119 + } + ] + } + ] + }, + { + "slug": "dynamic", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "dynamic", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- dynamic", + "line-number": 154 + } + ] + } + ] + }, + { + "slug": "local-functions", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "local-functions", + "track-neutral-concept": "reference/concepts/nested_functions.md", + "original-concepts": [ + { + "name": " - [Local functions][local_functions]", + "line-number": 49 + } + ] + } + ] + }, + { + "slug": "boxing", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "boxing", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Boxing/unboxing", + "line-number": 94 + } + ] + } + ] + }, + { + "slug": "slicing", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "slicing", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Slicing", + "line-number": 125 + } + ] + } + ] + }, + { + "slug": "unsafe-code", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "unsafe-code", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Unsafe code", + "line-number": 130 + } + ] + } + ] + }, + { + "slug": "lazy\u003CT\u003E", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "lazy\u003CT\u003E", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Lazy\u0026lt;T\u0026gt;", + "line-number": 159 + } + ] + } + ] + }, + { + "slug": "pointers", + "level": "advanced", + "completion-status": "newExerciseIssueRaised", + "document-link": "https://github.com/exercism/v3/issues/1147", + "concepts": [ + { + "name": "pointsers", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Pointers", + "line-number": 165 + } + ] + } + ] + }, + { + "slug": "multi-dimensional-array", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "multi-dimensional-array", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - multi-dimensional array (incl Array.CreateInstance", + "line-number": 142 + } + ] + } + ] + }, + { + "slug": "immutability", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "immutability", + "track-neutral-concept": "reference/concepts/immutability.md", + "original-concepts": [ + { + "name": " - [Immutability][immutability] - public readonly structs", + "line-number": 50 + } + ] + } + ] + }, + { + "slug": "stacks", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "stacks", + "track-neutral-concept": "reference/types/stack.md", + "original-concepts": [ + { + "name": " - [Stacks][stack]", + "line-number": 150 + } + ] + } + ] + }, + { + "slug": "destructors", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "destructors", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Destructors", + "line-number": 22 + } + ] + } + ] + }, + { + "slug": "aysnc-iterators", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "aysnc-iterators", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Async iterators", + "line-number": 74 + } + ] + } + ] + }, + { + "slug": "ref-local", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "ref-local", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "ref local; ref return", + "line-number": 171 + } + ] + } + ] + }, + { + "slug": "dispose-pattern", + "level": "advanced", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "dispose-pattern", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "Dispose Pattern", + "line-number": 175 + } + ] + } + ] + }, + { + "slug": "unallocated-concepts", + "level": "none", + "completion-status": "none", + "document-link": "", + "concepts": [ + { + "name": "bitwise-manipulation", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Bitwise manipulation", + "line-number": 109 + } + ] + }, + { + "name": "generics-introduction", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Generics Introduction", + "line-number": 75 + } + ] + }, + { + "name": "conditionals-if", + "track-neutral-concept": "reference/concepts/conditionals.md", + "original-concepts": [ + { + "name": " - [Conditionals: if][conditionals]", + "line-number": 90 + } + ] + }, + { + "name": "conditionals-do-while", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Conditionals: do-while", + "line-number": 87 + } + ] + }, + { + "name": "ordering", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Ordering", + "line-number": 81 + } + ] + } + ] + } + ] +} From 0237274128f5750bc2625d6f231c422787d60ceb Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 25 Aug 2020 08:21:57 +0100 Subject: [PATCH 194/327] clean-concepts - allocated some unallocated concepts * clean-concepts allocated to exercises some unallocated concepts on exercise-report README.md clean-concepts WIP clean-concepts WIP * [CI] Format code * clean-concepts change `conditionals-if` to `if-statements` Co-authored-by: github-actions[bot] --- exercises/concept/arrays/.meta/design.md | 1 + exercises/concept/chars/.meta/design.md | 1 + exercises/concept/classes/.meta/design.md | 2 +- .../concept/constructors/.meta/design.md | 2 +- exercises/concept/enums/.meta/design.md | 2 +- .../expression-bodied-members/.meta/design.md | 2 +- .../floating-point-numbers/.meta/design.md | 1 + exercises/concept/inheritance/.meta/design.md | 2 +- exercises/concept/nullability/.meta/design.md | 2 +- exercises/concept/numbers/.meta/design.md | 2 +- exercises/concept/parameters/.meta/design.md | 2 +- exercises/concept/time/.meta/design.md | 2 +- exercises/concept/tuples/.meta/design.md | 1 - .../user-defined-exceptions/.meta/design.md | 2 +- reference/exercises.json | 78 +++++++++---------- 15 files changed, 49 insertions(+), 53 deletions(-) diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/arrays/.meta/design.md index 34ec77d170..4e5c49c4a5 100644 --- a/exercises/concept/arrays/.meta/design.md +++ b/exercises/concept/arrays/.meta/design.md @@ -35,3 +35,4 @@ This exercise's prerequisites Concepts are: - `classes`: know how to work with fields. - `booleans`: know what a `bool` is. - `basics`: know how to work with `integers` and how to assign and update variables. +- `if-statements`: diff --git a/exercises/concept/chars/.meta/design.md b/exercises/concept/chars/.meta/design.md index e129ece710..13c770a1bd 100644 --- a/exercises/concept/chars/.meta/design.md +++ b/exercises/concept/chars/.meta/design.md @@ -26,3 +26,4 @@ - `strings`: know of the `string` type that will be iterated over and accessed by index. - `for-loop` for loops (rather than foreach) are the best means of highlighting the relationship between strings and `char`s +- `if-statements`: diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index db1b67b9d6..ff712986a7 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -30,4 +30,4 @@ - `basics`: know how to define a basic class with basic methods. - `strings`: know how to do basic string interpolation. - `numbers`: know how to compare numbers. -- `conditionals`: know how to do conditional logic. +- `if-statements`: know how to do conditional logic. diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/constructors/.meta/design.md index 5a9f755ddf..375174e3cc 100644 --- a/exercises/concept/constructors/.meta/design.md +++ b/exercises/concept/constructors/.meta/design.md @@ -19,5 +19,5 @@ - `classes`: know how to work with classes. - `numbers`: know how compare numbers. -- `conditionals`: know how to do conditional logic. +- `if-statements`: know how to do conditional logic. - `while-loops`: know how to use `while` loops. diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/enums/.meta/design.md index 807e413789..c414cc43a3 100644 --- a/exercises/concept/enums/.meta/design.md +++ b/exercises/concept/enums/.meta/design.md @@ -25,6 +25,6 @@ After completing this exercise, the student should: This exercise's prerequisites Concepts are: - `strings`: log lines are `string` values. -- `conditionals`: know how to execute conditional logic. +- `switch-statements`: [docs.microsoft.com-enum]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum diff --git a/exercises/concept/expression-bodied-members/.meta/design.md b/exercises/concept/expression-bodied-members/.meta/design.md index 9749e1def9..1e67ebe39b 100644 --- a/exercises/concept/expression-bodied-members/.meta/design.md +++ b/exercises/concept/expression-bodied-members/.meta/design.md @@ -25,7 +25,7 @@ - `constructors`: know how to define constructors. - `properties`: know how to define properties. - `booleans` -- `conditionals-if` +- `if-statements` - `exceptions` - `switch statements`: background for `switch expressions`. - `datetimes`: `DateTiime.Now` is used in example code. diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index 780f2cdd0c..b7b92bdde0 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -14,6 +14,7 @@ - `floating-point-numbers`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. - `while-loops`: know how to write a `while` loop. +- `if-statements`: ## Prerequisites diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index e965967e05..02935724e6 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -22,7 +22,7 @@ - `constructors`: know how to work with constructors. - `strings`: know how to do basic string interpolation. - `boolean`: know how to use boolean logic. -- `conditionals`: know how to do conditional logic. +- `if-statements`: know how to do conditional logic. ## Analyzer diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index 3a3ae4ef9d..dd466ce909 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -23,7 +23,7 @@ - `strings`: strings will be compared to `null` and basic methods from strings will be called. - `basics`: integers will be compared to `null`, arithmetic operations will be performed on integers, variables will be introduced and updated. -- `conditionals`: using a conditional statement. +- `if-statements`: using a conditional statement. - `memory-allocation`: reference and value types will be used in their nullable and non-nullable variants. [null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index b0efa68995..29f5805ce4 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -15,7 +15,7 @@ ## Concepts - `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to convert from one numeric type to another; know what implicit and explicit conversions are. -- `conditionals`: know how to conditionally execute code using an `if` statement. +- `if-statements`: know how to conditionally execute code using an `if` statement. ## Prerequisites diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/parameters/.meta/design.md index 8edaf9fbf2..dd6d1f29b6 100644 --- a/exercises/concept/parameters/.meta/design.md +++ b/exercises/concept/parameters/.meta/design.md @@ -20,7 +20,7 @@ This Concepts Exercise's Concepts are: This Concept Exercise's prerequisites Concepts are: -- `conditionals`: `if`, `else` +- `if-statements`: `if`, `else` - `numbers` - `strings` - `constructors`: the exercise provides a gentle intuitive introduction to simple parameters diff --git a/exercises/concept/time/.meta/design.md b/exercises/concept/time/.meta/design.md index b4a27456dd..fddca26362 100644 --- a/exercises/concept/time/.meta/design.md +++ b/exercises/concept/time/.meta/design.md @@ -22,6 +22,6 @@ - `datetime` - `switch-statements` - `strings` -- `conditionals-if` +- `if-statements` [noda-time]: https://nodatime.org/ diff --git a/exercises/concept/tuples/.meta/design.md b/exercises/concept/tuples/.meta/design.md index 2f05df06fb..c7ffdecce8 100644 --- a/exercises/concept/tuples/.meta/design.md +++ b/exercises/concept/tuples/.meta/design.md @@ -21,7 +21,6 @@ - `basics`: know how to define methods and variables. - `strings`: obtaining sub-strings from a string -- `conditionals`: combining conditions. ## Representer diff --git a/exercises/concept/user-defined-exceptions/.meta/design.md b/exercises/concept/user-defined-exceptions/.meta/design.md index 5812eb8e5f..9397af9929 100644 --- a/exercises/concept/user-defined-exceptions/.meta/design.md +++ b/exercises/concept/user-defined-exceptions/.meta/design.md @@ -22,6 +22,6 @@ This Concept Exercise's prerequisites Concepts are: - `exceptions`: know how to work with exceptions. - `inheritance`: inheriting from the `Exception` class for the custom exception. - `strings`: converting an into a string -- `conditionals`: use of simple `if`/`else` +- `if-statements`: use of `&&` - `arithmetic-overflow` - `signed-integers`: `Int32.MaxValue` diff --git a/reference/exercises.json b/reference/exercises.json index 3bea6a5fd4..278eb1565b 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -334,9 +334,13 @@ ] }, { - "name": "conditionals", - "track-neutral-concept": "", + "name": "if-statements", + "track-neutral-concept": "reference/concepts/conditionals.md", "original-concepts": [ + { + "name": " - [Conditionals: if][conditionals]", + "line-number": 90 + }, { "name": "- Conditionals", "line-number": 85 @@ -575,6 +579,16 @@ "completion-status": "complete", "document-link": "", "concepts": [ + { + "name": "bit-manipulation", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Bitwise manipulation", + "line-number": 109 + } + ] + }, { "name": "flag-enums", "track-neutral-concept": "", @@ -834,6 +848,16 @@ "line-number": 18 } ] + }, + { + "name": "ordering", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Ordering", + "line-number": 81 + } + ] } ] }, @@ -926,6 +950,16 @@ "line-number": 67 } ] + }, + { + "name": "generic-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": "- Generics Introduction", + "line-number": 75 + } + ] } ] }, @@ -2117,36 +2151,6 @@ "completion-status": "none", "document-link": "", "concepts": [ - { - "name": "bitwise-manipulation", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - Bitwise manipulation", - "line-number": 109 - } - ] - }, - { - "name": "generics-introduction", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": "- Generics Introduction", - "line-number": 75 - } - ] - }, - { - "name": "conditionals-if", - "track-neutral-concept": "reference/concepts/conditionals.md", - "original-concepts": [ - { - "name": " - [Conditionals: if][conditionals]", - "line-number": 90 - } - ] - }, { "name": "conditionals-do-while", "track-neutral-concept": "", @@ -2156,16 +2160,6 @@ "line-number": 87 } ] - }, - { - "name": "ordering", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - Ordering", - "line-number": 81 - } - ] } ] } From 972ba7af8bf9614022a02fa4245350a646c40707 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 25 Aug 2020 11:40:11 +0200 Subject: [PATCH 195/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index d08e12f228..853f21ab8f 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -50,16 +50,6 @@ "Message": "Failed to find concept exception-filtering, from the user-defined-exceptions design.md, in exercises.json file", "Source": "merge" }, - { - "Severity": "error", - "Message": "Failed to find concept bit-manipulation, from the flag-enums design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept generic-types, from the lists design.md, in exercises.json file", - "Source": "merge" - }, { "Severity": "error", "Message": "Failed to find concept datetime, from the datetimes design.md, in exercises.json file", From 8e6f8bce1ba02c75dbab0a71b5a45b13be5b55bb Mon Sep 17 00:00:00 2001 From: Mike May Date: Wed, 26 Aug 2020 15:49:55 +0100 Subject: [PATCH 196/327] clean concepts 2 * clean-concepts-2 added do-while-loop concept Added to floating-point-numbers exercise * clean-concepts-2 added do-while-loop concept Added to floating-point-numbers exercise --- .../floating-point-numbers/.docs/after.md | 16 +++++++++++++ .../floating-point-numbers/.meta/design.md | 4 +++- reference/exercises.json | 23 +++++++++---------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/exercises/concept/floating-point-numbers/.docs/after.md b/exercises/concept/floating-point-numbers/.docs/after.md index b39fb2d598..6c87e10f44 100644 --- a/exercises/concept/floating-point-numbers/.docs/after.md +++ b/exercises/concept/floating-point-numbers/.docs/after.md @@ -20,9 +20,25 @@ int x = 23; while (x > 10) { // Execute logic if x > 10 + x = x - 1; } ``` +A closely related construct is the `do` loop: + +```csharp +int x = 0; + +do +{ + x = GetX(); + // do something with x +} +while (x != 0); +``` + +This is used less frequently than a `while` loop but in some cases results in more natural looking code. + [docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions [docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions [docs-microsoft.com-characteristics-of-the-floating-point-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/floating-point-numbers/.meta/design.md index b7b92bdde0..6962fb50c2 100644 --- a/exercises/concept/floating-point-numbers/.meta/design.md +++ b/exercises/concept/floating-point-numbers/.meta/design.md @@ -3,6 +3,7 @@ - Know of the existence of the three floating point types: `double`, `float` and `decimal`. - Know when to use which floating point type. - Know how to write a `while` loop. +- know how to write a `do` loop. ## Out of scope @@ -14,7 +15,7 @@ - `floating-point-numbers`: know of the existing of the three floating point types: `double`, `float` and `decimal`. know when to use which floating point type. - `while-loops`: know how to write a `while` loop. -- `if-statements`: +- `do-while-loops`: know the syntax of `do` loop; know when to use a `do` loop ## Prerequisites @@ -22,5 +23,6 @@ This exercise's prerequisites Concepts are: - `numbers`: define numbers and apply arithmetic and boolean logic to them. - `conditionals`: conditionally execute code based on value of floating-point numbers. +- `if-statements`: [docs.microsoft.com-floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types diff --git a/reference/exercises.json b/reference/exercises.json index 278eb1565b..dcaffef815 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -552,6 +552,16 @@ "line-number": 89 } ] + }, + { + "name": "do-while-loops", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Conditionals: do-while", + "line-number": 87 + } + ] } ] }, @@ -2150,18 +2160,7 @@ "level": "none", "completion-status": "none", "document-link": "", - "concepts": [ - { - "name": "conditionals-do-while", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - Conditionals: do-while", - "line-number": 87 - } - ] - } - ] + "concepts": [] } ] } From f3e87547f947c50d9f2eee37e61ca4ea71be918e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 26 Aug 2020 10:52:28 -0400 Subject: [PATCH 197/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index 853f21ab8f..9f5ed9825b 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -1,5 +1,10 @@ { "Errors": [ + { + "Severity": "error", + "Message": "concepts: missing for unallocated-concepts\n", + "Source": "exercise" + }, { "Severity": "error", "Message": "nested-types: invalid format: - \u0060nested-types\u0060", From 941d948f2c420cfc12a71bbbb41168d850a0deb3 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 27 Aug 2020 08:01:33 +0100 Subject: [PATCH 198/327] invalid-design-format Fix poorly formatted design.md files --- exercises/concept/nested-types/.meta/design.md | 2 +- exercises/concept/regular-expressions/.meta/design.md | 2 +- exercises/concept/resource-lifetime/.meta/design.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/exercises/concept/nested-types/.meta/design.md b/exercises/concept/nested-types/.meta/design.md index d71dd5640c..53a2e4e40a 100644 --- a/exercises/concept/nested-types/.meta/design.md +++ b/exercises/concept/nested-types/.meta/design.md @@ -9,7 +9,7 @@ ## Concepts -- `nested-types` +- `nested-types`: know syntax for nested classes; know when to use nested classes; familiarity with other nested types such as structs and enums ## Prerequisites diff --git a/exercises/concept/regular-expressions/.meta/design.md b/exercises/concept/regular-expressions/.meta/design.md index 8a219eea22..1cb02f3472 100644 --- a/exercises/concept/regular-expressions/.meta/design.md +++ b/exercises/concept/regular-expressions/.meta/design.md @@ -12,7 +12,7 @@ ## Concepts -- `regular-expressions` as they are handled in C# and .NET. +- `regular-expressions`: Know how to use regular expressions with `Regex` in C#; Know how to identify the presence of a pattern in a string; Know how to "capture" and replace text identified by patterns; Know how to use the `Options` property of `Regex`; Know that search performance can be enhanced by compiling `Regex` (discussion only) ## Prerequisites diff --git a/exercises/concept/resource-lifetime/.meta/design.md b/exercises/concept/resource-lifetime/.meta/design.md index bb6083837a..91bec19fbb 100644 --- a/exercises/concept/resource-lifetime/.meta/design.md +++ b/exercises/concept/resource-lifetime/.meta/design.md @@ -6,7 +6,7 @@ ## Concepts -- `resource-lifetime` as it is handled in C#. +- `resource-lifetime`: Know how to control a resource's lifetime with the `using` statement in C# ## Prerequisites From d63a369cd431f759e61da1a578e5cea41913c9b8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2020 03:04:45 -0400 Subject: [PATCH 199/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index 9f5ed9825b..e63a02b8fe 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -5,21 +5,6 @@ "Message": "concepts: missing for unallocated-concepts\n", "Source": "exercise" }, - { - "Severity": "error", - "Message": "nested-types: invalid format: - \u0060nested-types\u0060", - "Source": "design" - }, - { - "Severity": "error", - "Message": "regular-expressions: invalid format: - \u0060regular-expressions\u0060 as they are handled in C# and .NET.", - "Source": "design" - }, - { - "Severity": "error", - "Message": "resource-lifetime: invalid format: - \u0060resource-lifetime\u0060 as it is handled in C#.", - "Source": "design" - }, { "Severity": "error", "Message": "Failed to find concept StringBuilder, from the chars design.md, in exercises.json file", @@ -245,26 +230,11 @@ "Message": "The string-builder concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", "Source": "missingLearningObjective" }, - { - "Severity": "error", - "Message": "The regular-expressions concept has no learning objectives on the exercise report - update the design.md for the regular-expressions exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The resource-lifetime concept has no learning objectives on the exercise report - update the design.md for the resource-lifetime exercise", - "Source": "missingLearningObjective" - }, { "Severity": "error", "Message": "The overflow concept has no learning objectives on the exercise report - update the design.md for the overflow exercise", "Source": "missingLearningObjective" }, - { - "Severity": "error", - "Message": "The nested-types concept has no learning objectives on the exercise report - update the design.md for the nested-types exercise", - "Source": "missingLearningObjective" - }, { "Severity": "error", "Message": "The implicit-casting concept has no learning objectives on the exercise report - update the design.md for the casting exercise", From 09262a01a889711502e2050fdabab1f5d344931b Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 28 Aug 2020 13:01:09 +0100 Subject: [PATCH 200/327] clean concepts 3 * clean-concepts-3 string-builder * clean-concepts-3 accessibility * clean-concepts-3 readonly-collections * clean-concepts-3 defensive-copying * clean-concepts-3 pattern-matching-constants * clean-concepts-3 while-loops * clean-concepts-3 exception-filtering * clean-concepts-3 datetime * clean-concepts-3 throw-expressions * clean-concepts-3 switch-expressions * clean-concepts-3 optional-parameters * clean-concepts-3 timezone * clean-concepts-3 overflows --- exercises/concept/datetimes/.meta/design.md | 2 +- exercises/concept/overflow/.meta/design.md | 2 +- .../concept/string-formatting/.meta/design.md | 3 +- reference/exercises.json | 67 ++++++++++++++++--- 4 files changed, 60 insertions(+), 14 deletions(-) diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/datetimes/.meta/design.md index ef0b32d677..b85d0a8a2d 100644 --- a/exercises/concept/datetimes/.meta/design.md +++ b/exercises/concept/datetimes/.meta/design.md @@ -18,7 +18,7 @@ ## Concepts -- `datetime`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa; know of the existence of the `DateTime` type; know of the individual, time-related properties. +- `datetimes`: know how to create a `DateTime` instance; know how to get the current date; know of the individual, date-related properties; know how to access the current date; know how to compare dates; know how to convert a `string` to a `DateTime` and vice versa; know of the existence of the `DateTime` type; know of the individual, time-related properties. ## Prerequisites diff --git a/exercises/concept/overflow/.meta/design.md b/exercises/concept/overflow/.meta/design.md index 695df09856..b1f100a0fe 100644 --- a/exercises/concept/overflow/.meta/design.md +++ b/exercises/concept/overflow/.meta/design.md @@ -10,7 +10,7 @@ ## Concepts -- `overflows`: explain integral number overflows; explain floating-point number overflows; know how to use `checked` and `unchecked` to deal with overflows. +- `overflow`: explain integral number overflows; explain floating-point number overflows; know how to use `checked` and `unchecked` to deal with overflows. ## Prerequisites diff --git a/exercises/concept/string-formatting/.meta/design.md b/exercises/concept/string-formatting/.meta/design.md index 769846dbfd..4657536554 100644 --- a/exercises/concept/string-formatting/.meta/design.md +++ b/exercises/concept/string-formatting/.meta/design.md @@ -14,7 +14,7 @@ ## Concepts -- `string-formatting`: know how to use the `ToString()` method to convert any object to a `string`; know how to use string interpolation on values of any type; know how to use default format strings to convert to standard output formats; know how to use custom format strings to convert to custom output formats; know that `string.Format` underlies string interpolation; know of the `StringBuilder` type and when to use it; know that string interpolation can interpolate any expression. +- `string-formatting`: know how to use the `ToString()` method to convert any object to a `string`; know how to use string interpolation on values of any type; know how to use default format strings to convert to standard output formats; know how to use custom format strings to convert to custom output formats; know that `string.Format` underlies string interpolation; know that string interpolation can interpolate any expression. - `verbatim-strings`: the syntax of verbatim strings. ## Prerequisites @@ -24,3 +24,4 @@ - `const-readonly` - `time`: for use of `CultureInfo`. - `varargs`: for the common overload of `public static string Format (string format, params object[] args);` +- `string-builder`: know of the `StringBuilder` type and when to use it diff --git a/reference/exercises.json b/reference/exercises.json index dcaffef815..975cb00283 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -238,6 +238,11 @@ "line-number": 28 } ] + }, + { + "name": "optional-parameters", + "track-neutral-concept": "", + "original-concepts": [] } ] }, @@ -422,6 +427,16 @@ "line-number": 139 } ] + }, + { + "name": "string-builder", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - StringBuilder", + "line-number": 129 + } + ] } ] }, @@ -524,6 +539,11 @@ "line-number": 155 } ] + }, + { + "name": "pattern-matching-constants", + "track-neutral-concept": "", + "original-concepts": [] } ] }, @@ -544,7 +564,7 @@ ] }, { - "name": "conditionals-while", + "name": "while-loops", "track-neutral-concept": "", "original-concepts": [ { @@ -626,6 +646,11 @@ "line-number": 59 } ] + }, + { + "name": "exception-filtering", + "track-neutral-concept": "", + "original-concepts": [] } ] }, @@ -821,6 +846,11 @@ } ] }, + { + "name": "timezone", + "track-neutral-concept": "", + "original-concepts": [] + }, { "name": "cross-platform", "track-neutral-concept": "", @@ -914,6 +944,16 @@ "line-number": 92 } ] + }, + { + "name": "readonly-collections", + "track-neutral-concept": "", + "original-concepts": [] + }, + { + "name": "defensive-copying", + "track-neutral-concept": "", + "original-concepts": [] } ] }, @@ -1016,6 +1056,16 @@ "line-number": 91 } ] + }, + { + "name": "throw-expressions", + "track-neutral-concept": "", + "original-concepts": [] + }, + { + "name": "switch-expressions", + "track-neutral-concept": "", + "original-concepts": [] } ] }, @@ -1035,6 +1085,11 @@ } ] }, + { + "name": "accessibility", + "track-neutral-concept": "", + "original-concepts": [] + }, { "name": "imports", "track-neutral-concept": "", @@ -1083,16 +1138,6 @@ } ] }, - { - "name": "string-builder", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - StringBuilder", - "line-number": 129 - } - ] - }, { "name": "verbatim-strings", "track-neutral-concept": "", From c73c940962f39e32277a60963a02c2a383ddc5ad Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 28 Aug 2020 14:04:25 +0200 Subject: [PATCH 201/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 79 +--------------------------------- 1 file changed, 2 insertions(+), 77 deletions(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index e63a02b8fe..7c2bf18617 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -10,66 +10,6 @@ "Message": "Failed to find concept StringBuilder, from the chars design.md, in exercises.json file", "Source": "merge" }, - { - "Severity": "error", - "Message": "Failed to find concept accessibility, from the namespaces design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept readonly-collections, from the constants design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept defensive-copying, from the constants design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept pattern-matching-constants, from the enums design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept while-loops, from the floating-point-numbers design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept exception-filtering, from the user-defined-exceptions design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept datetime, from the datetimes design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept throw-expressions, from the expression-bodied-members design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept switch-expressions, from the expression-bodied-members design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept optional-parameters, from the method-overloading design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept timezone, from the time design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "Failed to find concept overflows, from the overflow design.md, in exercises.json file", - "Source": "merge" - }, { "Severity": "error", "Message": "The encapsulation concept has no learning objectives on the exercise report - update the design.md for the classes exercise", @@ -167,17 +107,12 @@ }, { "Severity": "error", - "Message": "The base-class-library concept has no learning objectives on the exercise report - update the design.md for the dictionaries exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The datetimes concept has no learning objectives on the exercise report - update the design.md for the datetimes exercise", + "Message": "The string-builder concept has no learning objectives on the exercise report - update the design.md for the chars exercise", "Source": "missingLearningObjective" }, { "Severity": "error", - "Message": "The conditionals-while concept has no learning objectives on the exercise report - update the design.md for the floating-point-numbers exercise", + "Message": "The base-class-library concept has no learning objectives on the exercise report - update the design.md for the dictionaries exercise", "Source": "missingLearningObjective" }, { @@ -225,16 +160,6 @@ "Message": "The interpolation concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", "Source": "missingLearningObjective" }, - { - "Severity": "error", - "Message": "The string-builder concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The overflow concept has no learning objectives on the exercise report - update the design.md for the overflow exercise", - "Source": "missingLearningObjective" - }, { "Severity": "error", "Message": "The implicit-casting concept has no learning objectives on the exercise report - update the design.md for the casting exercise", From 5d36a8c037cd83488acc8c98f8b4e0dc7ae74af0 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 2 Sep 2020 11:01:10 +0200 Subject: [PATCH 202/327] Fix example of strings exercise --- exercises/concept/strings/.meta/Example.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/strings/.meta/Example.cs index a2e9bed840..74c9e5904f 100644 --- a/exercises/concept/strings/.meta/Example.cs +++ b/exercises/concept/strings/.meta/Example.cs @@ -7,7 +7,7 @@ public static string Message(string logLine) public static string LogLevel(string logLine) { - return logLine.Substring(1, (logLine.IndexOf("]") - 1).ToLower(); + return logLine.Substring(1, logLine.IndexOf("]") - 1).ToLower(); } public static string Reformat(string logLine) From f986ecb4d1770e83dcbd9e91870bd0f1121ca2de Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 2 Sep 2020 11:01:25 +0200 Subject: [PATCH 203/327] Fix invalid example test name for dictionaries exercise --- exercises/concept/dictionaries/.meta/Example.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/dictionaries/.meta/Example.cs b/exercises/concept/dictionaries/.meta/Example.cs index 528ffd9eb2..11763e5bee 100644 --- a/exercises/concept/dictionaries/.meta/Example.cs +++ b/exercises/concept/dictionaries/.meta/Example.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -public static class DialingCodes_example +public static class DialingCodes { public static Dictionary GetEmptyDictionary() { From d5ad19a2c4d5f15e2ecead2c136d7934915f7708 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 3 Sep 2020 09:46:38 +0100 Subject: [PATCH 204/327] clean-concepts-4 added concepts to design.md docs * clean-concepts-4 added concepts to design.md docs * Update languages/exercises/concept/classes/.meta/design.md Co-authored-by: Erik Schierboom Co-authored-by: Erik Schierboom --- exercises/concept/basics/.meta/design.md | 6 +++++ exercises/concept/casting/.meta/design.md | 1 + exercises/concept/chars/.meta/design.md | 2 +- exercises/concept/classes/.meta/design.md | 6 +++++ .../concept/dictionaries/.meta/design.md | 1 + exercises/concept/equality/.meta/design.md | 1 + exercises/concept/inheritance/.meta/design.md | 1 + .../concept/integral-numbers/.meta/design.md | 1 + exercises/concept/interfaces/.meta/design.md | 1 + exercises/concept/lists/.meta/design.md | 1 + exercises/concept/namespaces/.meta/design.md | 1 + exercises/concept/nullability/.meta/design.md | 4 ++++ exercises/concept/numbers/.meta/design.md | 2 ++ exercises/concept/parameters/.meta/design.md | 2 ++ .../concept/string-formatting/.meta/design.md | 3 ++- reference/exercises.json | 23 ++++++++++--------- 16 files changed, 43 insertions(+), 13 deletions(-) diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/basics/.meta/design.md index 164a921bcc..36242ae0eb 100644 --- a/exercises/concept/basics/.meta/design.md +++ b/exercises/concept/basics/.meta/design.md @@ -32,6 +32,12 @@ - `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. - `type-inference`: know how to use the keyword, `var`; know when it is appropriate to use type-inference +- `return-values`: know the syntax of the return statement +- `mutation`: know how OO state is maintained and updated in C# +- `functions`: know the syntax of a function call; know the syntax of a function declaration; understand the role of functions within OO +- `comments`: know the syntax of a single line comment; know the syntax of a multi-line comment +- `scoping`: know how scope works, what is in scope and out of scope at any point in the code +- `variables`: know how to declare a variable; know how to use a variable ## Prerequisites diff --git a/exercises/concept/casting/.meta/design.md b/exercises/concept/casting/.meta/design.md index 89770a2ecd..0f9d6d0e75 100644 --- a/exercises/concept/casting/.meta/design.md +++ b/exercises/concept/casting/.meta/design.md @@ -14,6 +14,7 @@ ## Concepts - `casting`: know what explicit and implicit casts are; know how to do an explicit cast; know how to use `is` and `as` to convert between types. +- `implicit-casting`: know about implicit type conversion ## Prerequisites diff --git a/exercises/concept/chars/.meta/design.md b/exercises/concept/chars/.meta/design.md index 13c770a1bd..848db58daf 100644 --- a/exercises/concept/chars/.meta/design.md +++ b/exercises/concept/chars/.meta/design.md @@ -20,7 +20,7 @@ ## Concepts - `chars`: know of the existence of the `char` type; know that a `char` represents; know how to define a `char`; know how to access a `char` in a string by index; know of some basic `char` methods (like converting to uppercase). -- `StringBuilder`: know how to use this. +- `string-builder`: know how to use a StringBuilder; know that it is more performant than simple concatenation ## Prerequisites diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/classes/.meta/design.md index ff712986a7..197062e007 100644 --- a/exercises/concept/classes/.meta/design.md +++ b/exercises/concept/classes/.meta/design.md @@ -24,6 +24,12 @@ ## Concepts - `classes`: know what classes are; know what encapsulation is; know what fields are; know how to create an object; know how to update state through methods; know about the `void` type. +- `encapsulation`: know how to encapsulate date; know what advantages encapsulation provides +- `fields`: know the syntax and behavior of fields +- `objects`: know what an object is; know how objects relate to classes +- `state`: know how state is maintained within a class +- `visibility`: know about private and public visibility; know the advantage of keeping visibility to a minimum +- `default-value`: know that an uninitialized field has a default value ## Prerequisites diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/dictionaries/.meta/design.md index 8910f3ef31..fa9a712e7f 100644 --- a/exercises/concept/dictionaries/.meta/design.md +++ b/exercises/concept/dictionaries/.meta/design.md @@ -21,6 +21,7 @@ ## Concepts - `dictionaries`: know of the existence of the `Dictionary` type; know how to define a dictionary; know how to add and updated elements in a dictionary; know how to access elements in a dictionary by key; know how to iterate over elements in a dictionary; know some basic dictionary functions. +- `base-class-library`: know of the existence and role of the base class library ## Prerequisites diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/equality/.meta/design.md index 93cf87be5b..6c0cb8353c 100644 --- a/exercises/concept/equality/.meta/design.md +++ b/exercises/concept/equality/.meta/design.md @@ -18,6 +18,7 @@ This Concepts Exercise's Concepts are: - `equality`: know how to check for equality and inequality; know how reference equality differs from structural equality; know that equality works by default for value and reference types; know how to customize equality checks using `Equals` and `GetHashCode()`; know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them. - `sets`: Know how to use hash sets `HashSet` as provided by the .NET BCL. Understand the relationship with `Object.GetHashCode()` and the performance charateristics of hash sets. +- `marker-interfaces`: know what a marker interface is; know of some common marker interfaces ## Prerequisites diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/inheritance/.meta/design.md index 02935724e6..822a3489f6 100644 --- a/exercises/concept/inheritance/.meta/design.md +++ b/exercises/concept/inheritance/.meta/design.md @@ -15,6 +15,7 @@ ## Concepts - `inheritance`: know what inheritance is; know how to inherit from a class; know that all types inherit from `object`; know what abstract and sealed classes are; know what abstract and virtual methods are; know how to override methods; know about the `protected` visibility modifier. +- `polymorphism`: know the syntax rules of virtual methods; understand the power of polymorphism ## Prerequisites diff --git a/exercises/concept/integral-numbers/.meta/design.md b/exercises/concept/integral-numbers/.meta/design.md index aacb3bcae4..b875d5b409 100644 --- a/exercises/concept/integral-numbers/.meta/design.md +++ b/exercises/concept/integral-numbers/.meta/design.md @@ -14,6 +14,7 @@ - `integral-numbers`: know of the difference between signed and unsigned integral types; know of the existence of the integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long` and `ulong`; know when to use which integral type. - `casting`: Understand casting of integral numeric types. +- `unsigned-integers`: know the characteristics of unsigned integers ## Prerequisites diff --git a/exercises/concept/interfaces/.meta/design.md b/exercises/concept/interfaces/.meta/design.md index 1c8070c179..f559772c9a 100644 --- a/exercises/concept/interfaces/.meta/design.md +++ b/exercises/concept/interfaces/.meta/design.md @@ -12,6 +12,7 @@ - `interfaces`: know what interfaces are; know how to use interfaces; know how to define an interface; know how to implement an interface; know how to explicitly implement an interface. - `ordering` : know how to implement the `IComparable` interface and what its effect is on the behaviour of collections. +- `explicit-interfaces`: know how an explicit interface is declared; know how use an explicit interface; know why explicit interfaces are useful ## Prerequisites diff --git a/exercises/concept/lists/.meta/design.md b/exercises/concept/lists/.meta/design.md index 8880eec65e..7e64c50d6f 100644 --- a/exercises/concept/lists/.meta/design.md +++ b/exercises/concept/lists/.meta/design.md @@ -24,6 +24,7 @@ - `lists`: know of the existence of the `List` type; know how a list is different from an array; know how to define a list; know how to add and remove elements from a list; know how to access elements in a list by their index; know how to iterate over elements in a list; know some basic list functions (like finding the index of an element in a list). - `generic-types`: know what generic types are. +- `collections`: know the role of collections in OO languages ## Prerequisites diff --git a/exercises/concept/namespaces/.meta/design.md b/exercises/concept/namespaces/.meta/design.md index 558bea9b08..3cb7cf8bf2 100644 --- a/exercises/concept/namespaces/.meta/design.md +++ b/exercises/concept/namespaces/.meta/design.md @@ -11,6 +11,7 @@ - `namespaces`: know what namespaces are; know how to import namespaces. - `accessibility`: know how to use access modifiers to limit access to elements. +- `imports`: know how to import namespaces with the `using` directive ## Prerequisites diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index dd466ce909..ec4b5cb578 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -18,6 +18,10 @@ ## Concepts - `nullability`: know of the existence of the `null` literal; know what a `NullReferenceException` is and when it is thrown; know how to compare a value to `null`; know the difference between value and reference types regarding nullability; know how to define nullable reference and value types; know about the null-related operators; know about basic null checking by the compiler. +- `null-coalescing`: know the syntax and behavior of the null-coalescing operator (??) +- `null-conditional`: know the syntax and behavior of the null-conditional operator (?.) +- `null-forgiving`: know the syntax and behvior of the null-forgiving operator (!.); know to use the operator with discretion +- `nullable-values`: know wbout nullable primitives; know about nullable structs ## Prerequisites diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/numbers/.meta/design.md index 29f5805ce4..0c20b2d46c 100644 --- a/exercises/concept/numbers/.meta/design.md +++ b/exercises/concept/numbers/.meta/design.md @@ -16,6 +16,8 @@ - `numbers`: know of the existence of the two most commonly used number types, `int` and `double`; understand that the former represents whole numbers, and the latter floating-point numbers; know of basic operators such as multiplication, comparison and equality; know how to convert from one numeric type to another; know what implicit and explicit conversions are. - `if-statements`: know how to conditionally execute code using an `if` statement. +- `math-operators`: know the math operators; know about precedence; know the role of parentheses +- `assignment`: know the syntax and behavior of assignment in OO languages ## Prerequisites diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/parameters/.meta/design.md index dd6d1f29b6..136b5c10c4 100644 --- a/exercises/concept/parameters/.meta/design.md +++ b/exercises/concept/parameters/.meta/design.md @@ -15,6 +15,8 @@ This Concepts Exercise's Concepts are: - `parameters`: know the difference between value and reference type parameters; know how to pass value types by reference using the `ref` and `out` modifiers. +- `out-parameters`: know the syntax of `out` parameters; know the role of `out` parameters +- `optional-arguments`: know the syntax and behavior or optional arguments ## Prerequisites diff --git a/exercises/concept/string-formatting/.meta/design.md b/exercises/concept/string-formatting/.meta/design.md index 4657536554..afbfaf4977 100644 --- a/exercises/concept/string-formatting/.meta/design.md +++ b/exercises/concept/string-formatting/.meta/design.md @@ -15,7 +15,8 @@ ## Concepts - `string-formatting`: know how to use the `ToString()` method to convert any object to a `string`; know how to use string interpolation on values of any type; know how to use default format strings to convert to standard output formats; know how to use custom format strings to convert to custom output formats; know that `string.Format` underlies string interpolation; know that string interpolation can interpolate any expression. -- `verbatim-strings`: the syntax of verbatim strings. +- `verbatim-strings`: the syntax of verbatim strings +- `interpolation`: know how the syntax of interpolated strings; know when to use string interpolation ## Prerequisites diff --git a/reference/exercises.json b/reference/exercises.json index 975cb00283..e21d2a95e8 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -1118,16 +1118,6 @@ } ] }, - { - "name": "formatting-types", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - Formatting types", - "line-number": 127 - } - ] - }, { "name": "interpolation", "track-neutral-concept": "", @@ -2205,7 +2195,18 @@ "level": "none", "completion-status": "none", "document-link": "", - "concepts": [] + "concepts": [ + { + "name": "formatting-types", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Formatting types", + "line-number": 127 + } + ] + } + ] } ] } From c216391a71d0fe3a4ad8e6b3898304afea05031f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 3 Sep 2020 04:50:17 -0400 Subject: [PATCH 205/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 168 +-------------------------------- 1 file changed, 1 insertion(+), 167 deletions(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index 7c2bf18617..81d6e36724 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -1,169 +1,3 @@ { - "Errors": [ - { - "Severity": "error", - "Message": "concepts: missing for unallocated-concepts\n", - "Source": "exercise" - }, - { - "Severity": "error", - "Message": "Failed to find concept StringBuilder, from the chars design.md, in exercises.json file", - "Source": "merge" - }, - { - "Severity": "error", - "Message": "The encapsulation concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The fields concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The objects concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The state concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The visibility concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The default-value concept has no learning objectives on the exercise report - update the design.md for the classes exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The polymorphism concept has no learning objectives on the exercise report - update the design.md for the inheritance exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The return-values concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The mutation concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The functions concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The comments concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The scoping concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The variables concept has no learning objectives on the exercise report - update the design.md for the basics exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The null-coalescing concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The null-conditional concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The null-forgiving concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The nullable-values concept has no learning objectives on the exercise report - update the design.md for the nullability exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The math-operators concept has no learning objectives on the exercise report - update the design.md for the numbers exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The assignment concept has no learning objectives on the exercise report - update the design.md for the numbers exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The string-builder concept has no learning objectives on the exercise report - update the design.md for the chars exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The base-class-library concept has no learning objectives on the exercise report - update the design.md for the dictionaries exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The marker-interfaces concept has no learning objectives on the exercise report - update the design.md for the equality exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The out-parameters concept has no learning objectives on the exercise report - update the design.md for the parameters exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The optional-arguments concept has no learning objectives on the exercise report - update the design.md for the parameters exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The explicit-interfaces concept has no learning objectives on the exercise report - update the design.md for the interfaces exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The unsigned-integers concept has no learning objectives on the exercise report - update the design.md for the integral-numbers exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The collections concept has no learning objectives on the exercise report - update the design.md for the lists exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The imports concept has no learning objectives on the exercise report - update the design.md for the namespaces exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The formatting-types concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The interpolation concept has no learning objectives on the exercise report - update the design.md for the string-formatting exercise", - "Source": "missingLearningObjective" - }, - { - "Severity": "error", - "Message": "The implicit-casting concept has no learning objectives on the exercise report - update the design.md for the casting exercise", - "Source": "missingLearningObjective" - } - ] + "Errors": [] } From f27ce25645230691f13c8fd2a0ec0ca1db929ce3 Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 11 Sep 2020 08:46:22 +0100 Subject: [PATCH 206/327] Update after.md Fixed typo --- exercises/concept/interfaces/.docs/after.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/concept/interfaces/.docs/after.md b/exercises/concept/interfaces/.docs/after.md index bd3b08fa7b..771fe01c66 100644 --- a/exercises/concept/interfaces/.docs/after.md +++ b/exercises/concept/interfaces/.docs/after.md @@ -50,7 +50,7 @@ public class ItalianTravellerV2 : IItalianLanguage return "migliorata - Ciao mondo"; } - public string SpeakItalisn() + public string SpeakItalian() { return Speak(); } From 7f68ac5035c6336dc754c2bd2a2d0b3f864a9b11 Mon Sep 17 00:00:00 2001 From: Mike May Date: Thu, 17 Sep 2020 12:30:40 +0100 Subject: [PATCH 207/327] issue #2250 mismatch between exercises.json and config.json * not-in-exercise-report initial commit * not-in-exercise-report addressed review points --- exercises/concept/flag-enums/.meta/design.md | 1 + .../concept/integral-numbers/.meta/design.md | 2 +- exercises/concept/parameters/.meta/design.md | 2 +- reference/exercises.json | 20 +++++++++---------- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/flag-enums/.meta/design.md index c08fa24824..82c6244cb1 100644 --- a/exercises/concept/flag-enums/.meta/design.md +++ b/exercises/concept/flag-enums/.meta/design.md @@ -16,6 +16,7 @@ As this is an advanced exercise, there are no enum-related things that we should - `flag-enums`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum. - `bit-manipulation`: know how to use bitwise operators to manipulate bits. +- `compound-assignment`: know how to use compound assignments )`&=`, etc) ## Prerequisites diff --git a/exercises/concept/integral-numbers/.meta/design.md b/exercises/concept/integral-numbers/.meta/design.md index b875d5b409..43aae5b88f 100644 --- a/exercises/concept/integral-numbers/.meta/design.md +++ b/exercises/concept/integral-numbers/.meta/design.md @@ -13,10 +13,10 @@ ## Concepts - `integral-numbers`: know of the difference between signed and unsigned integral types; know of the existence of the integral types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `long` and `ulong`; know when to use which integral type. -- `casting`: Understand casting of integral numeric types. - `unsigned-integers`: know the characteristics of unsigned integers ## Prerequisites - `numbers`: define numbers and apply arithmetic and logic to them. - `arrays`: byte array is used in the exercises. +- `casting`: Understand casting of integral numeric types. diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/parameters/.meta/design.md index 136b5c10c4..b7d66b24c1 100644 --- a/exercises/concept/parameters/.meta/design.md +++ b/exercises/concept/parameters/.meta/design.md @@ -26,4 +26,4 @@ This Concept Exercise's prerequisites Concepts are: - `numbers` - `strings` - `constructors`: the exercise provides a gentle intuitive introduction to simple parameters -- `named-parameters`: introduced in the `method-overloading` exercise and used here in _instructions.md_. +- `named-arguments`: introduced in the `method-overloading` exercise and used here in _instructions.md_. diff --git a/reference/exercises.json b/reference/exercises.json index e21d2a95e8..524d3f76b5 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -243,6 +243,16 @@ "name": "optional-parameters", "track-neutral-concept": "", "original-concepts": [] + }, + { + "name": "named-arguments", + "track-neutral-concept": "", + "original-concepts": [ + { + "name": " - Named arguments", + "line-number": 25 + } + ] } ] }, @@ -744,16 +754,6 @@ } ] }, - { - "name": "named-arguments", - "track-neutral-concept": "", - "original-concepts": [ - { - "name": " - Named arguments", - "line-number": 25 - } - ] - }, { "name": "out-parameters", "track-neutral-concept": "", From b212dd68881febcb5eb652547da67be71b53144a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 17 Sep 2020 13:52:31 +0200 Subject: [PATCH 208/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index 81d6e36724..e3d71af596 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -1,3 +1,9 @@ { - "Errors": [] + "Errors": [ + { + "Severity": "error", + "Message": "Failed to find concept compound-assignment, from the flag-enums design.md, in exercises.json file", + "Source": "merge" + } + ] } From 5dfbafbc13aad215c78e87f4d7000a4eec083185 Mon Sep 17 00:00:00 2001 From: Pablo Vicente Date: Sat, 10 Oct 2020 21:07:37 +0200 Subject: [PATCH 209/327] Fix typos on exceptions concept exercise --- exercises/concept/exceptions/.docs/instructions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/concept/exceptions/.docs/instructions.md b/exercises/concept/exceptions/.docs/instructions.md index 7f49b44564..c01346028b 100644 --- a/exercises/concept/exceptions/.docs/instructions.md +++ b/exercises/concept/exceptions/.docs/instructions.md @@ -12,10 +12,10 @@ SimpleCalculator.Calculate(512, 4, "/"); // => returns "512 / 4 = 128" ## 1. Handle the code that may throw errors within the method Calculate -The main method for implementation in this task will be the (_static_) `SimpleCalculator.Calculate()` method. It takes three arguments. The first two arguments are integer numbers on which an operation is going to be conducted. The third argument is of type string and for this excercise it is necessary to implement the following operations: +The main method for implementation in this task will be the (_static_) `SimpleCalculator.Calculate()` method. It takes three arguments. The first two arguments are integer numbers on which an operation is going to be conducted. The third argument is of type string and for this exercise it is necessary to implement the following operations: - addition using the `+` string -- multiplication using the `-` string +- multiplication using the `*` string - division using the `/` string ## 2. Handle illegal operations From 86f175c939e904e3cc1a8d7362074bd4b43e894a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 14 Oct 2020 18:05:44 +0200 Subject: [PATCH 210/327] Add stubs for concept documents --- concepts/accessibility/about.md | 1 + concepts/accessibility/links.json | 1 + concepts/arithmetic-overflow/about.md | 1 + concepts/arithmetic-overflow/links.json | 1 + concepts/arrays/about.md | 1 + concepts/arrays/links.json | 1 + concepts/attributes/about.md | 1 + concepts/attributes/links.json | 1 + concepts/basics/about.md | 1 + concepts/basics/links.json | 1 + concepts/bit-manipulation/about.md | 1 + concepts/bit-manipulation/links.json | 1 + concepts/booleans/about.md | 1 + concepts/booleans/links.json | 1 + concepts/casting/about.md | 1 + concepts/casting/links.json | 1 + concepts/chars/about.md | 1 + concepts/chars/links.json | 1 + concepts/classes/about.md | 1 + concepts/classes/links.json | 1 + concepts/compound-assignment/about.md | 1 + concepts/compound-assignment/links.json | 1 + concepts/conditionals-ternary/about.md | 1 + concepts/conditionals-ternary/links.json | 1 + concepts/const-readonly/about.md | 1 + concepts/const-readonly/links.json | 1 + concepts/constants/about.md | 1 + concepts/constants/links.json | 1 + concepts/constructors/about.md | 1 + concepts/constructors/links.json | 1 + concepts/datetime/about.md | 1 + concepts/datetime/links.json | 1 + concepts/datetimes/about.md | 1 + concepts/datetimes/links.json | 1 + concepts/defensive-copying/about.md | 1 + concepts/defensive-copying/links.json | 1 + concepts/dictionaries/about.md | 1 + concepts/dictionaries/links.json | 1 + concepts/do-while-loops/about.md | 1 + concepts/do-while-loops/links.json | 1 + concepts/enums/about.md | 1 + concepts/enums/links.json | 1 + concepts/equality/about.md | 1 + concepts/equality/links.json | 1 + concepts/exception-filtering/about.md | 1 + concepts/exception-filtering/links.json | 1 + concepts/exceptions/about.md | 1 + concepts/exceptions/links.json | 1 + concepts/explicit-casts/about.md | 1 + concepts/explicit-casts/links.json | 1 + concepts/expression-bodied-members/about.md | 1 + concepts/expression-bodied-members/links.json | 1 + concepts/flag-enums/about.md | 1 + concepts/flag-enums/links.json | 1 + concepts/floating-point-numbers/about.md | 1 + concepts/floating-point-numbers/links.json | 1 + concepts/for-loops/about.md | 1 + concepts/for-loops/links.json | 1 + concepts/foreach-loops/about.md | 1 + concepts/foreach-loops/links.json | 1 + concepts/generic-types/about.md | 1 + concepts/generic-types/links.json | 1 + concepts/if-statements/about.md | 1 + concepts/if-statements/links.json | 1 + concepts/indexers/about.md | 1 + concepts/indexers/links.json | 1 + concepts/inheritance/about.md | 1 + concepts/inheritance/links.json | 1 + concepts/integral-numbers/about.md | 1 + concepts/integral-numbers/links.json | 1 + concepts/interfaces/about.md | 1 + concepts/interfaces/links.json | 1 + concepts/lists/about.md | 1 + concepts/lists/links.json | 1 + concepts/memory-allocation/about.md | 1 + concepts/memory-allocation/links.json | 1 + concepts/method-overloading/about.md | 1 + concepts/method-overloading/links.json | 1 + concepts/named-arguments/about.md | 1 + concepts/named-arguments/links.json | 1 + concepts/namespaces/about.md | 1 + concepts/namespaces/links.json | 1 + concepts/nested-types/about.md | 1 + concepts/nested-types/links.json | 1 + concepts/nullability/about.md | 1 + concepts/nullability/links.json | 1 + concepts/numbers/about.md | 1 + concepts/numbers/links.json | 1 + concepts/object-initializers/about.md | 1 + concepts/object-initializers/links.json | 1 + concepts/operator-overloading/about.md | 1 + concepts/operator-overloading/links.json | 1 + concepts/optional-parameters/about.md | 1 + concepts/optional-parameters/links.json | 1 + concepts/ordering/about.md | 1 + concepts/ordering/links.json | 1 + concepts/overflow/about.md | 1 + concepts/overflow/links.json | 1 + concepts/parameters/about.md | 1 + concepts/parameters/links.json | 1 + concepts/pattern-matching-constants/about.md | 1 + concepts/pattern-matching-constants/links.json | 1 + concepts/properties/about.md | 1 + concepts/properties/links.json | 1 + concepts/randomness/about.md | 1 + concepts/randomness/links.json | 1 + concepts/readonly-collections/about.md | 1 + concepts/readonly-collections/links.json | 1 + concepts/regular-expressions/about.md | 1 + concepts/regular-expressions/links.json | 1 + concepts/resource-cleanup/about.md | 1 + concepts/resource-cleanup/links.json | 1 + concepts/resource-lifetime/about.md | 1 + concepts/resource-lifetime/links.json | 1 + concepts/sets/about.md | 1 + concepts/sets/links.json | 1 + concepts/string-builder/about.md | 1 + concepts/string-builder/links.json | 1 + concepts/string-formatting/about.md | 1 + concepts/string-formatting/links.json | 1 + concepts/string-interpolation/about.md | 1 + concepts/string-interpolation/links.json | 1 + concepts/strings/about.md | 1 + concepts/strings/links.json | 1 + concepts/structs/about.md | 1 + concepts/structs/links.json | 1 + concepts/switch-expressions/about.md | 1 + concepts/switch-expressions/links.json | 1 + concepts/switch-statements/about.md | 1 + concepts/switch-statements/links.json | 1 + concepts/throw-expressions/about.md | 1 + concepts/throw-expressions/links.json | 1 + concepts/time/about.md | 1 + concepts/time/links.json | 1 + concepts/timezone/about.md | 1 + concepts/timezone/links.json | 1 + concepts/tuples/about.md | 1 + concepts/tuples/links.json | 1 + concepts/user-defined-exceptions/about.md | 1 + concepts/user-defined-exceptions/links.json | 1 + concepts/varargs/about.md | 1 + concepts/varargs/links.json | 1 + concepts/verbatim-strings/about.md | 1 + concepts/verbatim-strings/links.json | 1 + concepts/while-loops/about.md | 1 + concepts/while-loops/links.json | 1 + 146 files changed, 146 insertions(+) create mode 100644 concepts/accessibility/about.md create mode 100644 concepts/accessibility/links.json create mode 100644 concepts/arithmetic-overflow/about.md create mode 100644 concepts/arithmetic-overflow/links.json create mode 100644 concepts/arrays/about.md create mode 100644 concepts/arrays/links.json create mode 100644 concepts/attributes/about.md create mode 100644 concepts/attributes/links.json create mode 100644 concepts/basics/about.md create mode 100644 concepts/basics/links.json create mode 100644 concepts/bit-manipulation/about.md create mode 100644 concepts/bit-manipulation/links.json create mode 100644 concepts/booleans/about.md create mode 100644 concepts/booleans/links.json create mode 100644 concepts/casting/about.md create mode 100644 concepts/casting/links.json create mode 100644 concepts/chars/about.md create mode 100644 concepts/chars/links.json create mode 100644 concepts/classes/about.md create mode 100644 concepts/classes/links.json create mode 100644 concepts/compound-assignment/about.md create mode 100644 concepts/compound-assignment/links.json create mode 100644 concepts/conditionals-ternary/about.md create mode 100644 concepts/conditionals-ternary/links.json create mode 100644 concepts/const-readonly/about.md create mode 100644 concepts/const-readonly/links.json create mode 100644 concepts/constants/about.md create mode 100644 concepts/constants/links.json create mode 100644 concepts/constructors/about.md create mode 100644 concepts/constructors/links.json create mode 100644 concepts/datetime/about.md create mode 100644 concepts/datetime/links.json create mode 100644 concepts/datetimes/about.md create mode 100644 concepts/datetimes/links.json create mode 100644 concepts/defensive-copying/about.md create mode 100644 concepts/defensive-copying/links.json create mode 100644 concepts/dictionaries/about.md create mode 100644 concepts/dictionaries/links.json create mode 100644 concepts/do-while-loops/about.md create mode 100644 concepts/do-while-loops/links.json create mode 100644 concepts/enums/about.md create mode 100644 concepts/enums/links.json create mode 100644 concepts/equality/about.md create mode 100644 concepts/equality/links.json create mode 100644 concepts/exception-filtering/about.md create mode 100644 concepts/exception-filtering/links.json create mode 100644 concepts/exceptions/about.md create mode 100644 concepts/exceptions/links.json create mode 100644 concepts/explicit-casts/about.md create mode 100644 concepts/explicit-casts/links.json create mode 100644 concepts/expression-bodied-members/about.md create mode 100644 concepts/expression-bodied-members/links.json create mode 100644 concepts/flag-enums/about.md create mode 100644 concepts/flag-enums/links.json create mode 100644 concepts/floating-point-numbers/about.md create mode 100644 concepts/floating-point-numbers/links.json create mode 100644 concepts/for-loops/about.md create mode 100644 concepts/for-loops/links.json create mode 100644 concepts/foreach-loops/about.md create mode 100644 concepts/foreach-loops/links.json create mode 100644 concepts/generic-types/about.md create mode 100644 concepts/generic-types/links.json create mode 100644 concepts/if-statements/about.md create mode 100644 concepts/if-statements/links.json create mode 100644 concepts/indexers/about.md create mode 100644 concepts/indexers/links.json create mode 100644 concepts/inheritance/about.md create mode 100644 concepts/inheritance/links.json create mode 100644 concepts/integral-numbers/about.md create mode 100644 concepts/integral-numbers/links.json create mode 100644 concepts/interfaces/about.md create mode 100644 concepts/interfaces/links.json create mode 100644 concepts/lists/about.md create mode 100644 concepts/lists/links.json create mode 100644 concepts/memory-allocation/about.md create mode 100644 concepts/memory-allocation/links.json create mode 100644 concepts/method-overloading/about.md create mode 100644 concepts/method-overloading/links.json create mode 100644 concepts/named-arguments/about.md create mode 100644 concepts/named-arguments/links.json create mode 100644 concepts/namespaces/about.md create mode 100644 concepts/namespaces/links.json create mode 100644 concepts/nested-types/about.md create mode 100644 concepts/nested-types/links.json create mode 100644 concepts/nullability/about.md create mode 100644 concepts/nullability/links.json create mode 100644 concepts/numbers/about.md create mode 100644 concepts/numbers/links.json create mode 100644 concepts/object-initializers/about.md create mode 100644 concepts/object-initializers/links.json create mode 100644 concepts/operator-overloading/about.md create mode 100644 concepts/operator-overloading/links.json create mode 100644 concepts/optional-parameters/about.md create mode 100644 concepts/optional-parameters/links.json create mode 100644 concepts/ordering/about.md create mode 100644 concepts/ordering/links.json create mode 100644 concepts/overflow/about.md create mode 100644 concepts/overflow/links.json create mode 100644 concepts/parameters/about.md create mode 100644 concepts/parameters/links.json create mode 100644 concepts/pattern-matching-constants/about.md create mode 100644 concepts/pattern-matching-constants/links.json create mode 100644 concepts/properties/about.md create mode 100644 concepts/properties/links.json create mode 100644 concepts/randomness/about.md create mode 100644 concepts/randomness/links.json create mode 100644 concepts/readonly-collections/about.md create mode 100644 concepts/readonly-collections/links.json create mode 100644 concepts/regular-expressions/about.md create mode 100644 concepts/regular-expressions/links.json create mode 100644 concepts/resource-cleanup/about.md create mode 100644 concepts/resource-cleanup/links.json create mode 100644 concepts/resource-lifetime/about.md create mode 100644 concepts/resource-lifetime/links.json create mode 100644 concepts/sets/about.md create mode 100644 concepts/sets/links.json create mode 100644 concepts/string-builder/about.md create mode 100644 concepts/string-builder/links.json create mode 100644 concepts/string-formatting/about.md create mode 100644 concepts/string-formatting/links.json create mode 100644 concepts/string-interpolation/about.md create mode 100644 concepts/string-interpolation/links.json create mode 100644 concepts/strings/about.md create mode 100644 concepts/strings/links.json create mode 100644 concepts/structs/about.md create mode 100644 concepts/structs/links.json create mode 100644 concepts/switch-expressions/about.md create mode 100644 concepts/switch-expressions/links.json create mode 100644 concepts/switch-statements/about.md create mode 100644 concepts/switch-statements/links.json create mode 100644 concepts/throw-expressions/about.md create mode 100644 concepts/throw-expressions/links.json create mode 100644 concepts/time/about.md create mode 100644 concepts/time/links.json create mode 100644 concepts/timezone/about.md create mode 100644 concepts/timezone/links.json create mode 100644 concepts/tuples/about.md create mode 100644 concepts/tuples/links.json create mode 100644 concepts/user-defined-exceptions/about.md create mode 100644 concepts/user-defined-exceptions/links.json create mode 100644 concepts/varargs/about.md create mode 100644 concepts/varargs/links.json create mode 100644 concepts/verbatim-strings/about.md create mode 100644 concepts/verbatim-strings/links.json create mode 100644 concepts/while-loops/about.md create mode 100644 concepts/while-loops/links.json diff --git a/concepts/accessibility/about.md b/concepts/accessibility/about.md new file mode 100644 index 0000000000..cad71de6bb --- /dev/null +++ b/concepts/accessibility/about.md @@ -0,0 +1 @@ +TODO: add information on accessibility concept diff --git a/concepts/accessibility/links.json b/concepts/accessibility/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/accessibility/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/arithmetic-overflow/about.md b/concepts/arithmetic-overflow/about.md new file mode 100644 index 0000000000..866d543703 --- /dev/null +++ b/concepts/arithmetic-overflow/about.md @@ -0,0 +1 @@ +TODO: add information on arithmetic-overflow concept diff --git a/concepts/arithmetic-overflow/links.json b/concepts/arithmetic-overflow/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/arithmetic-overflow/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/arrays/about.md b/concepts/arrays/about.md new file mode 100644 index 0000000000..c54a50ebfc --- /dev/null +++ b/concepts/arrays/about.md @@ -0,0 +1 @@ +TODO: add information on arrays concept diff --git a/concepts/arrays/links.json b/concepts/arrays/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/arrays/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/attributes/about.md b/concepts/attributes/about.md new file mode 100644 index 0000000000..221347763c --- /dev/null +++ b/concepts/attributes/about.md @@ -0,0 +1 @@ +TODO: add information on attributes concept diff --git a/concepts/attributes/links.json b/concepts/attributes/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/attributes/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/basics/about.md b/concepts/basics/about.md new file mode 100644 index 0000000000..246577017b --- /dev/null +++ b/concepts/basics/about.md @@ -0,0 +1 @@ +TODO: add information on basics concept diff --git a/concepts/basics/links.json b/concepts/basics/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/basics/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/bit-manipulation/about.md b/concepts/bit-manipulation/about.md new file mode 100644 index 0000000000..f9f04742d0 --- /dev/null +++ b/concepts/bit-manipulation/about.md @@ -0,0 +1 @@ +TODO: add information on bit-manipulation concept diff --git a/concepts/bit-manipulation/links.json b/concepts/bit-manipulation/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/bit-manipulation/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md new file mode 100644 index 0000000000..d461152b95 --- /dev/null +++ b/concepts/booleans/about.md @@ -0,0 +1 @@ +TODO: add information on booleans concept diff --git a/concepts/booleans/links.json b/concepts/booleans/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/booleans/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/casting/about.md b/concepts/casting/about.md new file mode 100644 index 0000000000..0667536eb3 --- /dev/null +++ b/concepts/casting/about.md @@ -0,0 +1 @@ +TODO: add information on casting concept diff --git a/concepts/casting/links.json b/concepts/casting/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/casting/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/chars/about.md b/concepts/chars/about.md new file mode 100644 index 0000000000..1314ebaf1b --- /dev/null +++ b/concepts/chars/about.md @@ -0,0 +1 @@ +TODO: add information on chars concept diff --git a/concepts/chars/links.json b/concepts/chars/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/chars/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/classes/about.md b/concepts/classes/about.md new file mode 100644 index 0000000000..608d2f539e --- /dev/null +++ b/concepts/classes/about.md @@ -0,0 +1 @@ +TODO: add information on classes concept diff --git a/concepts/classes/links.json b/concepts/classes/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/classes/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/compound-assignment/about.md b/concepts/compound-assignment/about.md new file mode 100644 index 0000000000..5fabff98d2 --- /dev/null +++ b/concepts/compound-assignment/about.md @@ -0,0 +1 @@ +TODO: add information on compound-assignment concept diff --git a/concepts/compound-assignment/links.json b/concepts/compound-assignment/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/compound-assignment/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/conditionals-ternary/about.md b/concepts/conditionals-ternary/about.md new file mode 100644 index 0000000000..71e104bdb5 --- /dev/null +++ b/concepts/conditionals-ternary/about.md @@ -0,0 +1 @@ +TODO: add information on conditionals-ternary concept diff --git a/concepts/conditionals-ternary/links.json b/concepts/conditionals-ternary/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/conditionals-ternary/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/const-readonly/about.md b/concepts/const-readonly/about.md new file mode 100644 index 0000000000..b027443617 --- /dev/null +++ b/concepts/const-readonly/about.md @@ -0,0 +1 @@ +TODO: add information on const-readonly concept diff --git a/concepts/const-readonly/links.json b/concepts/const-readonly/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/const-readonly/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/constants/about.md b/concepts/constants/about.md new file mode 100644 index 0000000000..e0a19de3d8 --- /dev/null +++ b/concepts/constants/about.md @@ -0,0 +1 @@ +TODO: add information on constants concept diff --git a/concepts/constants/links.json b/concepts/constants/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/constants/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/constructors/about.md b/concepts/constructors/about.md new file mode 100644 index 0000000000..e4368b7dff --- /dev/null +++ b/concepts/constructors/about.md @@ -0,0 +1 @@ +TODO: add information on constructors concept diff --git a/concepts/constructors/links.json b/concepts/constructors/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/constructors/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/datetime/about.md b/concepts/datetime/about.md new file mode 100644 index 0000000000..51b8d67912 --- /dev/null +++ b/concepts/datetime/about.md @@ -0,0 +1 @@ +TODO: add information on datetime concept diff --git a/concepts/datetime/links.json b/concepts/datetime/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/datetime/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/datetimes/about.md b/concepts/datetimes/about.md new file mode 100644 index 0000000000..3bc9842e1b --- /dev/null +++ b/concepts/datetimes/about.md @@ -0,0 +1 @@ +TODO: add information on datetimes concept diff --git a/concepts/datetimes/links.json b/concepts/datetimes/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/datetimes/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/defensive-copying/about.md b/concepts/defensive-copying/about.md new file mode 100644 index 0000000000..0a810479c5 --- /dev/null +++ b/concepts/defensive-copying/about.md @@ -0,0 +1 @@ +TODO: add information on defensive-copying concept diff --git a/concepts/defensive-copying/links.json b/concepts/defensive-copying/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/defensive-copying/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/dictionaries/about.md b/concepts/dictionaries/about.md new file mode 100644 index 0000000000..e68f19fc89 --- /dev/null +++ b/concepts/dictionaries/about.md @@ -0,0 +1 @@ +TODO: add information on dictionaries concept diff --git a/concepts/dictionaries/links.json b/concepts/dictionaries/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/dictionaries/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/do-while-loops/about.md b/concepts/do-while-loops/about.md new file mode 100644 index 0000000000..0241010b57 --- /dev/null +++ b/concepts/do-while-loops/about.md @@ -0,0 +1 @@ +TODO: add information on do-while-loops concept diff --git a/concepts/do-while-loops/links.json b/concepts/do-while-loops/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/do-while-loops/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/enums/about.md b/concepts/enums/about.md new file mode 100644 index 0000000000..d497cddaa5 --- /dev/null +++ b/concepts/enums/about.md @@ -0,0 +1 @@ +TODO: add information on enums concept diff --git a/concepts/enums/links.json b/concepts/enums/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/enums/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/equality/about.md b/concepts/equality/about.md new file mode 100644 index 0000000000..58de80ddcf --- /dev/null +++ b/concepts/equality/about.md @@ -0,0 +1 @@ +TODO: add information on equality concept diff --git a/concepts/equality/links.json b/concepts/equality/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/equality/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/exception-filtering/about.md b/concepts/exception-filtering/about.md new file mode 100644 index 0000000000..215d1cbb62 --- /dev/null +++ b/concepts/exception-filtering/about.md @@ -0,0 +1 @@ +TODO: add information on exception-filtering concept diff --git a/concepts/exception-filtering/links.json b/concepts/exception-filtering/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/exception-filtering/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/exceptions/about.md b/concepts/exceptions/about.md new file mode 100644 index 0000000000..98dcbc456c --- /dev/null +++ b/concepts/exceptions/about.md @@ -0,0 +1 @@ +TODO: add information on exceptions concept diff --git a/concepts/exceptions/links.json b/concepts/exceptions/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/exceptions/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/explicit-casts/about.md b/concepts/explicit-casts/about.md new file mode 100644 index 0000000000..6be5afbbe0 --- /dev/null +++ b/concepts/explicit-casts/about.md @@ -0,0 +1 @@ +TODO: add information on explicit-casts concept diff --git a/concepts/explicit-casts/links.json b/concepts/explicit-casts/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/explicit-casts/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/expression-bodied-members/about.md b/concepts/expression-bodied-members/about.md new file mode 100644 index 0000000000..265512b866 --- /dev/null +++ b/concepts/expression-bodied-members/about.md @@ -0,0 +1 @@ +TODO: add information on expression-bodied-members concept diff --git a/concepts/expression-bodied-members/links.json b/concepts/expression-bodied-members/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/expression-bodied-members/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/flag-enums/about.md b/concepts/flag-enums/about.md new file mode 100644 index 0000000000..78007cea97 --- /dev/null +++ b/concepts/flag-enums/about.md @@ -0,0 +1 @@ +TODO: add information on flag-enums concept diff --git a/concepts/flag-enums/links.json b/concepts/flag-enums/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/flag-enums/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/floating-point-numbers/about.md b/concepts/floating-point-numbers/about.md new file mode 100644 index 0000000000..4b9cdcc49c --- /dev/null +++ b/concepts/floating-point-numbers/about.md @@ -0,0 +1 @@ +TODO: add information on floating-point-numbers concept diff --git a/concepts/floating-point-numbers/links.json b/concepts/floating-point-numbers/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/floating-point-numbers/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/for-loops/about.md b/concepts/for-loops/about.md new file mode 100644 index 0000000000..d16625c977 --- /dev/null +++ b/concepts/for-loops/about.md @@ -0,0 +1 @@ +TODO: add information on for-loops concept diff --git a/concepts/for-loops/links.json b/concepts/for-loops/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/for-loops/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/foreach-loops/about.md b/concepts/foreach-loops/about.md new file mode 100644 index 0000000000..704f42cd36 --- /dev/null +++ b/concepts/foreach-loops/about.md @@ -0,0 +1 @@ +TODO: add information on foreach-loops concept diff --git a/concepts/foreach-loops/links.json b/concepts/foreach-loops/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/foreach-loops/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/generic-types/about.md b/concepts/generic-types/about.md new file mode 100644 index 0000000000..8572374ee8 --- /dev/null +++ b/concepts/generic-types/about.md @@ -0,0 +1 @@ +TODO: add information on generic-types concept diff --git a/concepts/generic-types/links.json b/concepts/generic-types/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/generic-types/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/if-statements/about.md b/concepts/if-statements/about.md new file mode 100644 index 0000000000..7f6fbf8015 --- /dev/null +++ b/concepts/if-statements/about.md @@ -0,0 +1 @@ +TODO: add information on if-statements concept diff --git a/concepts/if-statements/links.json b/concepts/if-statements/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/if-statements/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/indexers/about.md b/concepts/indexers/about.md new file mode 100644 index 0000000000..dd326541f0 --- /dev/null +++ b/concepts/indexers/about.md @@ -0,0 +1 @@ +TODO: add information on indexers concept diff --git a/concepts/indexers/links.json b/concepts/indexers/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/indexers/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md new file mode 100644 index 0000000000..8d36c90764 --- /dev/null +++ b/concepts/inheritance/about.md @@ -0,0 +1 @@ +TODO: add information on inheritance concept diff --git a/concepts/inheritance/links.json b/concepts/inheritance/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/inheritance/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/integral-numbers/about.md b/concepts/integral-numbers/about.md new file mode 100644 index 0000000000..9d9295732e --- /dev/null +++ b/concepts/integral-numbers/about.md @@ -0,0 +1 @@ +TODO: add information on integral-numbers concept diff --git a/concepts/integral-numbers/links.json b/concepts/integral-numbers/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/integral-numbers/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/interfaces/about.md b/concepts/interfaces/about.md new file mode 100644 index 0000000000..5463e9d03a --- /dev/null +++ b/concepts/interfaces/about.md @@ -0,0 +1 @@ +TODO: add information on interfaces concept diff --git a/concepts/interfaces/links.json b/concepts/interfaces/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/interfaces/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/lists/about.md b/concepts/lists/about.md new file mode 100644 index 0000000000..a324a4ab76 --- /dev/null +++ b/concepts/lists/about.md @@ -0,0 +1 @@ +TODO: add information on lists concept diff --git a/concepts/lists/links.json b/concepts/lists/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/lists/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/memory-allocation/about.md b/concepts/memory-allocation/about.md new file mode 100644 index 0000000000..36a70fe8ce --- /dev/null +++ b/concepts/memory-allocation/about.md @@ -0,0 +1 @@ +TODO: add information on memory-allocation concept diff --git a/concepts/memory-allocation/links.json b/concepts/memory-allocation/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/memory-allocation/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/method-overloading/about.md b/concepts/method-overloading/about.md new file mode 100644 index 0000000000..679c8f4333 --- /dev/null +++ b/concepts/method-overloading/about.md @@ -0,0 +1 @@ +TODO: add information on method-overloading concept diff --git a/concepts/method-overloading/links.json b/concepts/method-overloading/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/method-overloading/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/named-arguments/about.md b/concepts/named-arguments/about.md new file mode 100644 index 0000000000..f005324d6b --- /dev/null +++ b/concepts/named-arguments/about.md @@ -0,0 +1 @@ +TODO: add information on named-arguments concept diff --git a/concepts/named-arguments/links.json b/concepts/named-arguments/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/named-arguments/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/namespaces/about.md b/concepts/namespaces/about.md new file mode 100644 index 0000000000..fa1b9f7ff0 --- /dev/null +++ b/concepts/namespaces/about.md @@ -0,0 +1 @@ +TODO: add information on namespaces concept diff --git a/concepts/namespaces/links.json b/concepts/namespaces/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/namespaces/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/nested-types/about.md b/concepts/nested-types/about.md new file mode 100644 index 0000000000..13bf1fa073 --- /dev/null +++ b/concepts/nested-types/about.md @@ -0,0 +1 @@ +TODO: add information on nested-types concept diff --git a/concepts/nested-types/links.json b/concepts/nested-types/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/nested-types/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/nullability/about.md b/concepts/nullability/about.md new file mode 100644 index 0000000000..b19fe3c214 --- /dev/null +++ b/concepts/nullability/about.md @@ -0,0 +1 @@ +TODO: add information on nullability concept diff --git a/concepts/nullability/links.json b/concepts/nullability/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/nullability/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md new file mode 100644 index 0000000000..36eb002377 --- /dev/null +++ b/concepts/numbers/about.md @@ -0,0 +1 @@ +TODO: add information on numbers concept diff --git a/concepts/numbers/links.json b/concepts/numbers/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/numbers/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/object-initializers/about.md b/concepts/object-initializers/about.md new file mode 100644 index 0000000000..e1eaca8302 --- /dev/null +++ b/concepts/object-initializers/about.md @@ -0,0 +1 @@ +TODO: add information on object-initializers concept diff --git a/concepts/object-initializers/links.json b/concepts/object-initializers/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/object-initializers/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/operator-overloading/about.md b/concepts/operator-overloading/about.md new file mode 100644 index 0000000000..73c270c9a0 --- /dev/null +++ b/concepts/operator-overloading/about.md @@ -0,0 +1 @@ +TODO: add information on operator-overloading concept diff --git a/concepts/operator-overloading/links.json b/concepts/operator-overloading/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/operator-overloading/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/optional-parameters/about.md b/concepts/optional-parameters/about.md new file mode 100644 index 0000000000..cbed9c5869 --- /dev/null +++ b/concepts/optional-parameters/about.md @@ -0,0 +1 @@ +TODO: add information on optional-parameters concept diff --git a/concepts/optional-parameters/links.json b/concepts/optional-parameters/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/optional-parameters/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/ordering/about.md b/concepts/ordering/about.md new file mode 100644 index 0000000000..9ce566ba38 --- /dev/null +++ b/concepts/ordering/about.md @@ -0,0 +1 @@ +TODO: add information on ordering concept diff --git a/concepts/ordering/links.json b/concepts/ordering/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/ordering/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/overflow/about.md b/concepts/overflow/about.md new file mode 100644 index 0000000000..9ca01eb292 --- /dev/null +++ b/concepts/overflow/about.md @@ -0,0 +1 @@ +TODO: add information on overflow concept diff --git a/concepts/overflow/links.json b/concepts/overflow/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/overflow/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/parameters/about.md b/concepts/parameters/about.md new file mode 100644 index 0000000000..3a469a0a37 --- /dev/null +++ b/concepts/parameters/about.md @@ -0,0 +1 @@ +TODO: add information on parameters concept diff --git a/concepts/parameters/links.json b/concepts/parameters/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/parameters/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/pattern-matching-constants/about.md b/concepts/pattern-matching-constants/about.md new file mode 100644 index 0000000000..b5ce60fc22 --- /dev/null +++ b/concepts/pattern-matching-constants/about.md @@ -0,0 +1 @@ +TODO: add information on pattern-matching-constants concept diff --git a/concepts/pattern-matching-constants/links.json b/concepts/pattern-matching-constants/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/pattern-matching-constants/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/properties/about.md b/concepts/properties/about.md new file mode 100644 index 0000000000..6cbb8a7d5a --- /dev/null +++ b/concepts/properties/about.md @@ -0,0 +1 @@ +TODO: add information on properties concept diff --git a/concepts/properties/links.json b/concepts/properties/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/properties/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md new file mode 100644 index 0000000000..5695c7a266 --- /dev/null +++ b/concepts/randomness/about.md @@ -0,0 +1 @@ +TODO: add information on randomness concept diff --git a/concepts/randomness/links.json b/concepts/randomness/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/randomness/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/readonly-collections/about.md b/concepts/readonly-collections/about.md new file mode 100644 index 0000000000..6c85a723ea --- /dev/null +++ b/concepts/readonly-collections/about.md @@ -0,0 +1 @@ +TODO: add information on readonly-collections concept diff --git a/concepts/readonly-collections/links.json b/concepts/readonly-collections/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/readonly-collections/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/regular-expressions/about.md b/concepts/regular-expressions/about.md new file mode 100644 index 0000000000..2e19654931 --- /dev/null +++ b/concepts/regular-expressions/about.md @@ -0,0 +1 @@ +TODO: add information on regular-expressions concept diff --git a/concepts/regular-expressions/links.json b/concepts/regular-expressions/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/regular-expressions/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/resource-cleanup/about.md b/concepts/resource-cleanup/about.md new file mode 100644 index 0000000000..8dfc2b5f55 --- /dev/null +++ b/concepts/resource-cleanup/about.md @@ -0,0 +1 @@ +TODO: add information on resource-cleanup concept diff --git a/concepts/resource-cleanup/links.json b/concepts/resource-cleanup/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/resource-cleanup/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/resource-lifetime/about.md b/concepts/resource-lifetime/about.md new file mode 100644 index 0000000000..452f7b049a --- /dev/null +++ b/concepts/resource-lifetime/about.md @@ -0,0 +1 @@ +TODO: add information on resource-lifetime concept diff --git a/concepts/resource-lifetime/links.json b/concepts/resource-lifetime/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/resource-lifetime/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/sets/about.md b/concepts/sets/about.md new file mode 100644 index 0000000000..bb43f192c2 --- /dev/null +++ b/concepts/sets/about.md @@ -0,0 +1 @@ +TODO: add information on sets concept diff --git a/concepts/sets/links.json b/concepts/sets/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/sets/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/string-builder/about.md b/concepts/string-builder/about.md new file mode 100644 index 0000000000..3d56ed28b7 --- /dev/null +++ b/concepts/string-builder/about.md @@ -0,0 +1 @@ +TODO: add information on string-builder concept diff --git a/concepts/string-builder/links.json b/concepts/string-builder/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/string-builder/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/string-formatting/about.md b/concepts/string-formatting/about.md new file mode 100644 index 0000000000..ffa8019a90 --- /dev/null +++ b/concepts/string-formatting/about.md @@ -0,0 +1 @@ +TODO: add information on string-formatting concept diff --git a/concepts/string-formatting/links.json b/concepts/string-formatting/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/string-formatting/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/string-interpolation/about.md b/concepts/string-interpolation/about.md new file mode 100644 index 0000000000..e24a721ed0 --- /dev/null +++ b/concepts/string-interpolation/about.md @@ -0,0 +1 @@ +TODO: add information on string-interpolation concept diff --git a/concepts/string-interpolation/links.json b/concepts/string-interpolation/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/string-interpolation/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/strings/about.md b/concepts/strings/about.md new file mode 100644 index 0000000000..b046260477 --- /dev/null +++ b/concepts/strings/about.md @@ -0,0 +1 @@ +TODO: add information on strings concept diff --git a/concepts/strings/links.json b/concepts/strings/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/strings/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/structs/about.md b/concepts/structs/about.md new file mode 100644 index 0000000000..907615fbdb --- /dev/null +++ b/concepts/structs/about.md @@ -0,0 +1 @@ +TODO: add information on structs concept diff --git a/concepts/structs/links.json b/concepts/structs/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/structs/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/switch-expressions/about.md b/concepts/switch-expressions/about.md new file mode 100644 index 0000000000..1ea714168d --- /dev/null +++ b/concepts/switch-expressions/about.md @@ -0,0 +1 @@ +TODO: add information on switch-expressions concept diff --git a/concepts/switch-expressions/links.json b/concepts/switch-expressions/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/switch-expressions/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/switch-statements/about.md b/concepts/switch-statements/about.md new file mode 100644 index 0000000000..3179a5c212 --- /dev/null +++ b/concepts/switch-statements/about.md @@ -0,0 +1 @@ +TODO: add information on switch-statements concept diff --git a/concepts/switch-statements/links.json b/concepts/switch-statements/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/switch-statements/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/throw-expressions/about.md b/concepts/throw-expressions/about.md new file mode 100644 index 0000000000..22d112a032 --- /dev/null +++ b/concepts/throw-expressions/about.md @@ -0,0 +1 @@ +TODO: add information on throw-expressions concept diff --git a/concepts/throw-expressions/links.json b/concepts/throw-expressions/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/throw-expressions/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/time/about.md b/concepts/time/about.md new file mode 100644 index 0000000000..5c95b2bfc4 --- /dev/null +++ b/concepts/time/about.md @@ -0,0 +1 @@ +TODO: add information on time concept diff --git a/concepts/time/links.json b/concepts/time/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/time/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/timezone/about.md b/concepts/timezone/about.md new file mode 100644 index 0000000000..417fe11300 --- /dev/null +++ b/concepts/timezone/about.md @@ -0,0 +1 @@ +TODO: add information on timezone concept diff --git a/concepts/timezone/links.json b/concepts/timezone/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/timezone/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/tuples/about.md b/concepts/tuples/about.md new file mode 100644 index 0000000000..477c9ba98c --- /dev/null +++ b/concepts/tuples/about.md @@ -0,0 +1 @@ +TODO: add information on tuples concept diff --git a/concepts/tuples/links.json b/concepts/tuples/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/tuples/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/user-defined-exceptions/about.md b/concepts/user-defined-exceptions/about.md new file mode 100644 index 0000000000..107b3955ef --- /dev/null +++ b/concepts/user-defined-exceptions/about.md @@ -0,0 +1 @@ +TODO: add information on user-defined-exceptions concept diff --git a/concepts/user-defined-exceptions/links.json b/concepts/user-defined-exceptions/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/user-defined-exceptions/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/varargs/about.md b/concepts/varargs/about.md new file mode 100644 index 0000000000..43a2024334 --- /dev/null +++ b/concepts/varargs/about.md @@ -0,0 +1 @@ +TODO: add information on varargs concept diff --git a/concepts/varargs/links.json b/concepts/varargs/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/varargs/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/verbatim-strings/about.md b/concepts/verbatim-strings/about.md new file mode 100644 index 0000000000..313184d669 --- /dev/null +++ b/concepts/verbatim-strings/about.md @@ -0,0 +1 @@ +TODO: add information on verbatim-strings concept diff --git a/concepts/verbatim-strings/links.json b/concepts/verbatim-strings/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/verbatim-strings/links.json @@ -0,0 +1 @@ +[] diff --git a/concepts/while-loops/about.md b/concepts/while-loops/about.md new file mode 100644 index 0000000000..a9cd4eb710 --- /dev/null +++ b/concepts/while-loops/about.md @@ -0,0 +1 @@ +TODO: add information on while-loops concept diff --git a/concepts/while-loops/links.json b/concepts/while-loops/links.json new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/concepts/while-loops/links.json @@ -0,0 +1 @@ +[] From acad53e63c02bbc7644c454009c3be9047b8296d Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Wed, 21 Oct 2020 11:05:00 +0200 Subject: [PATCH 211/327] remove enum from config and from the switch exercise remove enum from config an from the exercise switch --- .../concept/switch-statements/.docs/after.md | 8 ++- .../switch-statements/.docs/instructions.md | 18 +++--- .../switch-statements/.docs/introduction.md | 7 ++- .../switch-statements/.meta/Example.cs | 62 +++++++++++-------- .../switch-statements/.meta/config.json | 4 ++ .../concept/switch-statements/.meta/design.md | 2 +- .../switch-statements/SwitchStatements.cs | 21 +++++-- .../SwitchStatementsTests.cs | 46 ++++++++++---- 8 files changed, 110 insertions(+), 58 deletions(-) diff --git a/exercises/concept/switch-statements/.docs/after.md b/exercises/concept/switch-statements/.docs/after.md index 9e93b9d3a4..8261c86e02 100644 --- a/exercises/concept/switch-statements/.docs/after.md +++ b/exercises/concept/switch-statements/.docs/after.md @@ -29,10 +29,11 @@ Animal animal = GetAnimal(); switch(animal) { - case Dog dog: - dog.Bark(); + case Dog canine: + case Coyote canine: + canine.Bark(); break; - case Cat cat when cat.Had8Lives(): + case Cat cat when cat.HasOnly8Lives(): cat.IsCareful(); cat.Meow(); break; @@ -46,6 +47,7 @@ switch(animal) - The `break` statement is mandatory for any non-empty `case` clause. - Obviously the type of all the arguments to the `case` labels must be derived from the type of the `switch` argument. A `switch` argument of type `Object` obviously allows the widest range. - The guard expression can include anything in scope not just members of the `case` argument. +- Multiple `case` with different `case` arguments can refer to the same code block. [switch statement][switch-statement] documentation provides an introduction to `switch` statements. diff --git a/exercises/concept/switch-statements/.docs/instructions.md b/exercises/concept/switch-statements/.docs/instructions.md index 8add616a36..d34452f5e6 100644 --- a/exercises/concept/switch-statements/.docs/instructions.md +++ b/exercises/concept/switch-statements/.docs/instructions.md @@ -11,13 +11,13 @@ The player descriptions are as follows: 2 -> "left back" 3 & 4 "center back" 5 -> "right back" -6, 7, & 8 -> "midfielder" +6, 7 & 8 -> "midfielder" 9 -> "left wing" 10 -> "striker" 11 -> "right wing" ``` -Implement the static `PlayAnalyzer.OnField()` method to output a player description based on their shirt number. +Implement the static `PlayAnalyzer.AnalyzeOnField()` method to output a player description based on their shirt number. ```csharp PlayAnalyzer.AnalyzeOnField(10); @@ -26,11 +26,11 @@ PlayAnalyzer.AnalyzeOnField(10); ### 2. Raise an alert if an unknown shirt number is encountered. -Modify the `PlayAnalyzer.OffField()` method to throw an `ArgumentException` when a shirt number outside the range 1-11 is processed. +Modify the `PlayAnalyzer.AnalyzeOnField()` method to throw an `ArgumentException` when a shirt number outside the range 1-11 is processed. ### 3. Extend the coverage to include off field activity -Implement the `PlayAnalyzer.OffField()` method to output description of activities and characters around the field of play. +Implement the `PlayAnalyzer.AnalyzeOffField()` method to output description of activities and characters around the field of play. You receive a stream of data that has been cleaned. Your task is to analyse it and output appropriate text to help the journalists. @@ -38,19 +38,19 @@ The data comprises: - shirt numbers (any `int`) -> text as per on field analysis - free form text (any `string`) -> the text unchanged -- incidents in play (`Incident` enum) -> "RedCard", "Foul" etc. +- incidents in play (any subclass of the type `Incident`) -> "Injury", "Foul" etc. - opposing managers (objects of type `Manager`) -> "the manager" ```csharp -PlayAnalyzer.AnalyzeOffField(Incident.RedCard); -// => "RedCard" -PlayAnalyzer.AnalyzeOffField((new Manager()); +PlayAnalyzer.AnalyzeOffField(new Injury()); +// => "A player is injured. Medics are on the field." +PlayAnalyzer.AnalyzeOffField(new Manager()); // => "the manager" ``` ### 4. Where the manager has a name available we want that output instead of "the manager" -Modify the `PlayAnalyzer.OffField()` method to output any name such as "Jürgen Klopp" if there is one. If there is no name then the `Manager.Name` property is guaranteed to be an empty string rather than null. +Modify the `PlayAnalyzer.AnalyzeOffField()` method to output any name such as "Jürgen Klopp" if there is one. If there is no name then the `Manager.Name` property is guaranteed to be an empty string rather than null. ```csharp PlayAnalyzer.AnalyzeOffField(new Manager("José Mário dos Santos Mourinho Félix", string.Empty)) diff --git a/exercises/concept/switch-statements/.docs/introduction.md b/exercises/concept/switch-statements/.docs/introduction.md index 3ebf3e64b1..8395a6f1c9 100644 --- a/exercises/concept/switch-statements/.docs/introduction.md +++ b/exercises/concept/switch-statements/.docs/introduction.md @@ -27,10 +27,11 @@ Animal animal = GetAnimal(); switch (animal) { - case Dog dog: - dog.Bark(); + case Dog canine: + case Coyote canine: + canine.Bark(); break; - case Cat cat when cat.Had8Lives(): + case Cat cat when cat.HasOnly8Lives(): cat.IsCareful(); cat.Meow(); break; diff --git a/exercises/concept/switch-statements/.meta/Example.cs b/exercises/concept/switch-statements/.meta/Example.cs index ccf430b8f6..4eff6e9812 100644 --- a/exercises/concept/switch-statements/.meta/Example.cs +++ b/exercises/concept/switch-statements/.meta/Example.cs @@ -1,32 +1,10 @@ using System; -// **** please do not modify the Manager class **** -public class Manager -{ - public string Name { get; } - public string Activity { get; } - - public Manager(string name, string activity) - { - this.Name = name; - this.Activity = activity; - } -} - -// **** please do not modify the Incident enum **** -public enum Incident -{ - RedCard, - YellowCard, - Foul, - Injury -} - public static class PlayAnalyzer { public static string AnalyzeOnField(int shirtNum) { - string playerDescription = string.Empty; + string playerDescription; switch (shirtNum) { case 1: @@ -65,7 +43,7 @@ public static string AnalyzeOnField(int shirtNum) public static string AnalyzeOffField(object report) { - string description = string.Empty; + string description; switch (report) { case int shirtNum: @@ -74,8 +52,11 @@ public static string AnalyzeOffField(object report) case string freeFormText: description = freeFormText; break; + case Injury injury: + description = $"{injury.GetDescription()} Medics are on the field."; + break; case Incident incident: - description = incident.ToString(); + description = incident.GetDescription(); break; case Manager manager when !string.IsNullOrWhiteSpace(manager.Name): description = manager.Name; @@ -90,3 +71,34 @@ public static string AnalyzeOffField(object report) return description; } } + +// **** please do not modify the Manager class **** +public class Manager +{ + public string Name { get; } + public string Activity { get; } + + public Manager(string name, string activity) + { + this.Name = name; + this.Activity = activity; + } +} + +// **** please do not modify the Incident class or any subclasses **** +public class Incident +{ + public virtual string GetDescription() => "An incident happened."; +} + +// **** please do not modify the Foul class **** +public class Foul : Incident +{ + public override string GetDescription() => "The referee deemed a foul."; +} + +// **** please do not modify the Injury class **** +public class Injury : Incident +{ + public override string GetDescription() => "A player is injured."; +} \ No newline at end of file diff --git a/exercises/concept/switch-statements/.meta/config.json b/exercises/concept/switch-statements/.meta/config.json index 9212d455d1..c45cf94e8b 100644 --- a/exercises/concept/switch-statements/.meta/config.json +++ b/exercises/concept/switch-statements/.meta/config.json @@ -3,6 +3,10 @@ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" + }, + { + "github_username": "valentin-p", + "exercism_username": "valentin-p" } ], "authors": [ diff --git a/exercises/concept/switch-statements/.meta/design.md b/exercises/concept/switch-statements/.meta/design.md index e7f9f118ef..f26dbe90a8 100644 --- a/exercises/concept/switch-statements/.meta/design.md +++ b/exercises/concept/switch-statements/.meta/design.md @@ -8,6 +8,7 @@ - switch expressions - pattern matching tuples +- enums ## Concepts @@ -15,6 +16,5 @@ ## Prerequisites -- `enums` - `classes` - `inheritance`: with type pattern matching the student needs to be aware of the need for a common base type including `Object`. diff --git a/exercises/concept/switch-statements/SwitchStatements.cs b/exercises/concept/switch-statements/SwitchStatements.cs index 1c22962537..abfd96b1fa 100644 --- a/exercises/concept/switch-statements/SwitchStatements.cs +++ b/exercises/concept/switch-statements/SwitchStatements.cs @@ -26,11 +26,20 @@ public Manager(string name, string activity) } } -// **** please do not modify the Incident enum **** -public enum Incident +// **** please do not modify the Incident class or any subclasses **** +public class Incident { - RedCard, - YellowCard, - Foul, - Injury + public virtual string GetDescription() => "An incident happened."; +} + +// **** please do not modify the Foul class **** +public class Foul : Incident +{ + public override string GetDescription() => "The referee deemed a foul."; +} + +// **** please do not modify the Injury class **** +public class Injury : Incident +{ + public override string GetDescription() => "A player is injured."; } diff --git a/exercises/concept/switch-statements/SwitchStatementsTests.cs b/exercises/concept/switch-statements/SwitchStatementsTests.cs index 34c5486823..200a449f10 100644 --- a/exercises/concept/switch-statements/SwitchStatementsTests.cs +++ b/exercises/concept/switch-statements/SwitchStatementsTests.cs @@ -4,50 +4,74 @@ public class TuplesTest { [Fact] - public void OnField_10() + public void AnalyzeOnField_1() + { + Assert.Equal("goalie", PlayAnalyzer.AnalyzeOnField(1)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AnalyzeOnField_8() + { + Assert.Equal("midfielder", PlayAnalyzer.AnalyzeOnField(8)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AnalyzeOnField_10() { Assert.Equal("striker", PlayAnalyzer.AnalyzeOnField(10)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OnField_bad() + public void AnalyzeOnField_11() { - Assert.Throws(() => PlayAnalyzer.AnalyzeOnField(1729)); + Assert.Equal("right wing", PlayAnalyzer.AnalyzeOnField(11)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_1() + public void AnalyzeOnField_throws_unknown_shirt_number() { - Assert.Equal("goalie", PlayAnalyzer.AnalyzeOnField(1)); + Assert.Throws(() => PlayAnalyzer.AnalyzeOnField(1729)); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_text() + public void AnalyzeOffField_text() { Assert.Equal("They think it's all over!", PlayAnalyzer.AnalyzeOffField("They think it's all over!")); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_incident() + public void AnalyzeOffField_incident() + { + Assert.Equal("An incident happened.", PlayAnalyzer.AnalyzeOffField(new Incident())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AnalyzeOffField_foul() + { + Assert.Equal("The referee deemed a foul.", PlayAnalyzer.AnalyzeOffField(new Foul())); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void AnalyzeOffField_injury() { - Assert.Equal("Foul", PlayAnalyzer.AnalyzeOffField(Incident.Foul)); + Assert.Equal("A player is injured. Medics are on the field.", PlayAnalyzer.AnalyzeOffField(new Injury())); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_anonymous_manager() + public void AnalyzeOffField_anonymous_manager() { Assert.Equal("the manager", PlayAnalyzer.AnalyzeOffField(new Manager(string.Empty, string.Empty))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_named_manager() + public void AnalyzeOffField_named_manager() { Assert.Equal("José Mário dos Santos Mourinho Félix", PlayAnalyzer.AnalyzeOffField(new Manager("José Mário dos Santos Mourinho Félix", string.Empty))); } [Fact(Skip = "Remove this Skip property to run this test")] - public void OffField_bad() + public void AnalyzeOffField_throws_type_single() { Assert.Throws(() => PlayAnalyzer.AnalyzeOffField(90.0f)); } From 499d02e585dc028ad40ef43b00ab3d12a7ac109e Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 15:23:47 +0200 Subject: [PATCH 212/327] tuples - replace about.md file with concept files * Pre-populate tuples concept's about.md file from after.md file * Pre-populate tuples concept's links.json file from after.md file * tuples - Remove after.md document --- concepts/tuples/about.md | 156 +++++++++++++++++++++++- concepts/tuples/links.json | 47 ++++++- exercises/concept/tuples/.docs/after.md | 155 ----------------------- 3 files changed, 201 insertions(+), 157 deletions(-) delete mode 100644 exercises/concept/tuples/.docs/after.md diff --git a/concepts/tuples/about.md b/concepts/tuples/about.md index 477c9ba98c..6b989c403d 100644 --- a/concepts/tuples/about.md +++ b/concepts/tuples/about.md @@ -1 +1,155 @@ -TODO: add information on tuples concept +In C#, a tuple is a data structure which organizes data, holding two or more fields +of any type. + +A tuple is typically created by placing 2 or more expressions separated by comas, +within a set of parentheses. + +```csharp +string boast = "All you need to know"; +bool success = !string.IsNullOrWhiteSpace(boast); +(bool, int, string) tripple = (success, 42, boast); +``` + +As an expression like any other, a tuple can be used in a range of ways: in [assignments][tuple-assignment], +to initialize a field or variable, [return value][tuple-return-values] from a method or passed as a parameter. +They can be tested for [equality][tuple-equality]. Equality of tuples is illustrated fully in the `pattern-matching-tuples` exercise but an example is provided in the code below for the sake of completeness. + +Fields are extracted using dot syntax. By default, the first field is `Item1`, +the second `Item2`, etc. Non-default names are discussed below under _Naming_. + +A tuple can be used as a generic parameter, e.g. `IList<(bool, string)>` + +In addition, tuples support "deconstruction", discussed below +, and can be used in pattern matching which is covered in a later exercise. + +```csharp +// initialization +(int, int, int) vertices = (90, 45, 45); + +// assignment +vertices = (60, 60, 60); + +// return value +(bool, int) GetSameOrBigger(int num1, int num2) +{ + return (num1 == num2, num1 > num2 ? num1 : num2); +} + +// method argument +int Add((int, int) operands) +{ + return operands.Item1 + operands.Item2; +} + +// equality testing +var estimateA = (42, 1729); +var estimateB = (2*3*7, 7*13*19); +bool result = estimateA == estimateB; +// => result == true +``` + +This [introduction][tuples] shows how to define and use tuples. + +### Naming + +Field names `Item1` etc. do not make for readable code. There are 3 ways to +provide names to the fields a) in the type declaration or b) in the expression that +creates it, c) by means of [tuple projection initializers][tuple-projection-initializers] +(not illustrated here). + +```csharp +// name items in declaration +(bool success, string message) results = (true, "well done!"); +bool mySuccess = results.success; +string myMessaage = results.message; + +// name items in creating expression +var results2 = (success: true, message: "well done!"); +bool mySuccess2 = results2.success; +string myMessaage2 = results2.message; +``` + +Don't try to be too clever with the naming mechanism. It is really just syntactic +sugar. For example, you cannot change the names of a tuple when you assign to it +from another tuple. + +### Deconstruction + +Sometimes it is convenient to take a tuple and assign the fields to multiple variables +and initialize them if appropriate. +This mechanism is called [deconstruction][tuple-deconstruction]. (It can also +be applied to your own objects. See [here][udt-deconstruction]). + +```csharp +var goodNumbers = (42, 3.142, 1729); +(int ultimateQuestion, var π, var ramanujan) = goodNumbers; +return ultimateQuestion; +// => 42 +``` + +### Field Assignment + +The fields of tuples can be individually assigned to. +However, given the trend in C# towards immutability this +sort of usage is not widespread. Tuples are often used as if they were immutable +which of course they are not. + +```csharp +(int, string) tpl; +tpl.Item1 = 1; +tpl.Item2 = "bad"; +tpl.Item2 = "even worse"; +// => (1, "even worse"; +``` + +### Background + +The tuples we are discussing should not be confused with [`System.Tuple`][system-tuple] +which will probably be found only in legacy code bases. + +The position is slightly more confusing when it comes to `System.ValueTuple`. +The [docs][system-value-tuple] for the final overload of [`System.ValueTuple`][system-value-tuple]state that +"The value tuple types provide the runtime implementation that supports tuples in C# ". +By "value tuple types" here they are referring to the generic overloads of `System.ValueTuple`. +By "tuples" they mean the things that have concerned us in this exercise. +Effectively they are saying that `System.ValueTuple` is an implementation detail of tuples. This is +unlikely to be of much interest, most of the time, to most people. Unfortunately much of the +documentation on "tuples" including Microsoft's own is liberally sprinkled with references +to `System.ValueTuple`. It is probably safe to skate over such references. + +### Other Uses and Limitations + +Pattern matching is a particularly productive use for tuples. This +is covered in a later exercise. + +Tuples allow for some other minor stylistic flourishes: + +- Multiple assignment (particularly in constructors) .e.g `(this.field1, this.field2) = (arg1, arg2);` +- Swapping or recycling values e.g. `(a, b) = (b, a);` +- Use instead of a `struct` in a list +- Use as a dictionary key or the contents of a set. +- Use in LINQ. (LINQ is covered by later exercises). + +The documentation describes tuples as a lightweight mechanism and that is the key to +its successful use. Using a tuple instead of a class or struct can lead to tedious +repetition of its field types and possibly names. This applies particularly to +its use as a method argument or as the generic argument in collections. + +It is best to make use of tricks like multiple assignment and swapping judiciously. + +Relational operations other than equality and inequality are not supported. + +Note that tuples were introduced into the language relatively recently (C# 7) +so if you want to use them you should make sure your code base +is using [version][language-version] 7 or later of the language. + +[tuples]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples +[tuple-projection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuple-projection-initializers +[tuple-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples +[tuple-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#assignment-and-tuples +[tuple-return-values]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values +[tuple-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstruction +[udt-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstructing-user-defined-types +[system-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.tuple?view=netcore-3.1 +[system-value-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8?view=netcore-3.1 +[language-version]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version diff --git a/concepts/tuples/links.json b/concepts/tuples/links.json index fe51488c70..bcd9587e7f 100644 --- a/concepts/tuples/links.json +++ b/concepts/tuples/links.json @@ -1 +1,46 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#assignment-and-tuples", + "description": "tuple-assignment" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values", + "description": "tuple-return-values" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples", + "description": "tuple-equality" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples", + "description": "tuples" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuple-projection-initializers", + "description": "tuple-projection-initializers" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstruction", + "description": "tuple-deconstruction" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstructing-user-defined-types", + "description": "udt-deconstruction" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.tuple?view=netcore-3.1", + "description": "system-tuple" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8?view=netcore-3.1", + "description": "system-value-tuple" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8?view=netcore-3.1", + "description": "system-value-tuple" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version", + "description": "language-version" + } +] diff --git a/exercises/concept/tuples/.docs/after.md b/exercises/concept/tuples/.docs/after.md deleted file mode 100644 index 6b989c403d..0000000000 --- a/exercises/concept/tuples/.docs/after.md +++ /dev/null @@ -1,155 +0,0 @@ -In C#, a tuple is a data structure which organizes data, holding two or more fields -of any type. - -A tuple is typically created by placing 2 or more expressions separated by comas, -within a set of parentheses. - -```csharp -string boast = "All you need to know"; -bool success = !string.IsNullOrWhiteSpace(boast); -(bool, int, string) tripple = (success, 42, boast); -``` - -As an expression like any other, a tuple can be used in a range of ways: in [assignments][tuple-assignment], -to initialize a field or variable, [return value][tuple-return-values] from a method or passed as a parameter. -They can be tested for [equality][tuple-equality]. Equality of tuples is illustrated fully in the `pattern-matching-tuples` exercise but an example is provided in the code below for the sake of completeness. - -Fields are extracted using dot syntax. By default, the first field is `Item1`, -the second `Item2`, etc. Non-default names are discussed below under _Naming_. - -A tuple can be used as a generic parameter, e.g. `IList<(bool, string)>` - -In addition, tuples support "deconstruction", discussed below -, and can be used in pattern matching which is covered in a later exercise. - -```csharp -// initialization -(int, int, int) vertices = (90, 45, 45); - -// assignment -vertices = (60, 60, 60); - -// return value -(bool, int) GetSameOrBigger(int num1, int num2) -{ - return (num1 == num2, num1 > num2 ? num1 : num2); -} - -// method argument -int Add((int, int) operands) -{ - return operands.Item1 + operands.Item2; -} - -// equality testing -var estimateA = (42, 1729); -var estimateB = (2*3*7, 7*13*19); -bool result = estimateA == estimateB; -// => result == true -``` - -This [introduction][tuples] shows how to define and use tuples. - -### Naming - -Field names `Item1` etc. do not make for readable code. There are 3 ways to -provide names to the fields a) in the type declaration or b) in the expression that -creates it, c) by means of [tuple projection initializers][tuple-projection-initializers] -(not illustrated here). - -```csharp -// name items in declaration -(bool success, string message) results = (true, "well done!"); -bool mySuccess = results.success; -string myMessaage = results.message; - -// name items in creating expression -var results2 = (success: true, message: "well done!"); -bool mySuccess2 = results2.success; -string myMessaage2 = results2.message; -``` - -Don't try to be too clever with the naming mechanism. It is really just syntactic -sugar. For example, you cannot change the names of a tuple when you assign to it -from another tuple. - -### Deconstruction - -Sometimes it is convenient to take a tuple and assign the fields to multiple variables -and initialize them if appropriate. -This mechanism is called [deconstruction][tuple-deconstruction]. (It can also -be applied to your own objects. See [here][udt-deconstruction]). - -```csharp -var goodNumbers = (42, 3.142, 1729); -(int ultimateQuestion, var π, var ramanujan) = goodNumbers; -return ultimateQuestion; -// => 42 -``` - -### Field Assignment - -The fields of tuples can be individually assigned to. -However, given the trend in C# towards immutability this -sort of usage is not widespread. Tuples are often used as if they were immutable -which of course they are not. - -```csharp -(int, string) tpl; -tpl.Item1 = 1; -tpl.Item2 = "bad"; -tpl.Item2 = "even worse"; -// => (1, "even worse"; -``` - -### Background - -The tuples we are discussing should not be confused with [`System.Tuple`][system-tuple] -which will probably be found only in legacy code bases. - -The position is slightly more confusing when it comes to `System.ValueTuple`. -The [docs][system-value-tuple] for the final overload of [`System.ValueTuple`][system-value-tuple]state that -"The value tuple types provide the runtime implementation that supports tuples in C# ". -By "value tuple types" here they are referring to the generic overloads of `System.ValueTuple`. -By "tuples" they mean the things that have concerned us in this exercise. -Effectively they are saying that `System.ValueTuple` is an implementation detail of tuples. This is -unlikely to be of much interest, most of the time, to most people. Unfortunately much of the -documentation on "tuples" including Microsoft's own is liberally sprinkled with references -to `System.ValueTuple`. It is probably safe to skate over such references. - -### Other Uses and Limitations - -Pattern matching is a particularly productive use for tuples. This -is covered in a later exercise. - -Tuples allow for some other minor stylistic flourishes: - -- Multiple assignment (particularly in constructors) .e.g `(this.field1, this.field2) = (arg1, arg2);` -- Swapping or recycling values e.g. `(a, b) = (b, a);` -- Use instead of a `struct` in a list -- Use as a dictionary key or the contents of a set. -- Use in LINQ. (LINQ is covered by later exercises). - -The documentation describes tuples as a lightweight mechanism and that is the key to -its successful use. Using a tuple instead of a class or struct can lead to tedious -repetition of its field types and possibly names. This applies particularly to -its use as a method argument or as the generic argument in collections. - -It is best to make use of tricks like multiple assignment and swapping judiciously. - -Relational operations other than equality and inequality are not supported. - -Note that tuples were introduced into the language relatively recently (C# 7) -so if you want to use them you should make sure your code base -is using [version][language-version] 7 or later of the language. - -[tuples]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples -[tuple-projection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuple-projection-initializers -[tuple-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#equality-and-tuples -[tuple-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#assignment-and-tuples -[tuple-return-values]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#tuples-as-method-return-values -[tuple-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstruction -[udt-deconstruction]: https://docs.microsoft.com/en-us/dotnet/csharp/tuples#deconstructing-user-defined-types -[system-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.tuple?view=netcore-3.1 -[system-value-tuple]: https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8?view=netcore-3.1 -[language-version]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/configure-language-version From 5a3c7743689da50d3d500317cde6247f812c5e14 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 15:40:43 +0200 Subject: [PATCH 213/327] structs - replace about.md file with concept files * Pre-populate structs concept's about.md file from after.md file * Pre-populate structs concept's links.json file from after.md file * structs - Remove after.md document --- concepts/structs/about.md | 94 +++++++++++++++++++++++- concepts/structs/links.json | 35 ++++++++- exercises/concept/structs/.docs/after.md | 93 ----------------------- 3 files changed, 127 insertions(+), 95 deletions(-) delete mode 100644 exercises/concept/structs/.docs/after.md diff --git a/concepts/structs/about.md b/concepts/structs/about.md index 907615fbdb..05e95c3a4e 100644 --- a/concepts/structs/about.md +++ b/concepts/structs/about.md @@ -1 +1,93 @@ -TODO: add information on structs concept +C# `struct`s are closely related `class`s. They have state and behavior. They can have the same kinds of members: constructors, methods, fields, properties, etc. + +Fields and properties can be simple types, `struct`s or reference types. `struct`s observe the same rules about scope, read/write rules and access levels as do `class`s. + +```csharp +enum Unit +{ + Kg, + Lb +} + +struct Weight +{ + private double count; + private Unit unit; + + public Weight(double count, Unit unit) + { + this.count = count; + this.unit = unit; + } + + public override string ToString() + { + return count.ToString() + unit.ToString(); + } +} + +new Weight(77.5, Unit.Kg).ToString(); +// => "77.6Kg" +``` + +One of the main things to remember is that when one struct is assigned to a variable or passed as a parameter the values are copied across so changes to the original variable will not affect the copied one and vice versa. In summary, `struct`s are **value types**. + +This [article][class-or-struct] discusses the differences between `struct`s and `class`s. You will see from the article that `struct`s tend to be lightweight and [immutable][structs-immutable] although this guidance is not enforced (by default) by the compiler or runtime. + +There are a couple of things that you will come up against (and about which the compiler will remind you): + +1. Members of a `struct` cannot be initialized inline. +2. A `struct` cannot be inherited +3. A `struct` always has a default constructor even if a non-default one is provided, and you cannot provide an explicit parameterless constructor. + +As a result of points 1 and 3 above there is no way for the developer of a `struct` to prevent invalid instances from coming into existence. + +#### Common structs + +You will see from the documentation that there is a close relationship between primitives and structs. See [`Int32/int]`][int32], for an example. A more conventional example of a`struct`is the type [`TimeSpan`][time-span]. + +Instances of `TimeSpan` behave much like numbers with comparison operators like `>` and `<` and arithmetic operators. You can implement these operators for your own `struct`s when you need them. + +One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable`. Although `struct`s cannot be derived from other `struct`s they can implement interfaces. + +#### Equality + +Equality testing for `struct`s can often be much simpler than that for `class`s as it simply compares fields for equality by default. There is no need to override `object.Equals()` (or `GetHashCode()`). Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use. Effectively, this means that structs used in this way should be immutable. See (TODO cross-ref-tba). + +In contrast to the method, `Equals()`, there is no default implementation of the equality operators, `==` and `!=`. If your `struct` needs them then you will have to implement them. + +On the other hand, this [article][equality] describes how performance can be optimised by creating your own custom `Equals()` and `GetHashCode()` method as is often done with `class`s. The difference in the case of this exercise was about 20% in a not very rigorous comparison but that may be on the low side because all the fields are of the same type - see below. + +There are discussions on the [web][equality-performance] about speed improvements, where the `Equals()` method is not overridden, if all fields are of the same type. The difference in this exercise of including disparate fields was about 60%. This is not mentioned in Microsoft's documentation so that makes it an un-documented implementation detail, and it should be exploited judiciously. + +```csharp +public bool Equals(Weight other) +{ + return count.Equals(other.count) && unit.Equals(other.unit); +} + +public override bool Equals(object obj) +{ + return obj is Weight other && Equals(other); +} + +public override int GetHashCode() +{ + return HashCode.Combine(count, unit); +} +``` + +#### General + +- [structs][structs]: introduction to structs. +- [class-or-struct][class-or-struct]: lists the guidelines for choosing between a struct and class. + +[structs-immutable]: https://stackoverflow.com/a/3753640/96167 +[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type +[equality-performance]: https://medium.com/@semuserable/c-journey-into-struct-equality-comparison-deep-dive-9693f74562f1 +[structs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct +[class-or-struct]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct +[int32]: https://docs.microsoft.com/en-us/dotnet/api/system.int32?view=netcore-3.1 +[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-3.1 diff --git a/concepts/structs/links.json b/concepts/structs/links.json index fe51488c70..d765cc6e57 100644 --- a/concepts/structs/links.json +++ b/concepts/structs/links.json @@ -1 +1,34 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct", + "description": "class-or-struct" + }, + { + "url": "https://stackoverflow.com/a/3753640/96167", + "description": "structs-immutable" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.int32?view=netcore-3.1", + "description": "int32" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-3.1", + "description": "time-span" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type", + "description": "equality" + }, + { + "url": "https://medium.com/@semuserable/c-journey-into-struct-equality-comparison-deep-dive-9693f74562f1", + "description": "equality-performance" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct", + "description": "structs" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct", + "description": "class-or-struct" + } +] diff --git a/exercises/concept/structs/.docs/after.md b/exercises/concept/structs/.docs/after.md deleted file mode 100644 index 05e95c3a4e..0000000000 --- a/exercises/concept/structs/.docs/after.md +++ /dev/null @@ -1,93 +0,0 @@ -C# `struct`s are closely related `class`s. They have state and behavior. They can have the same kinds of members: constructors, methods, fields, properties, etc. - -Fields and properties can be simple types, `struct`s or reference types. `struct`s observe the same rules about scope, read/write rules and access levels as do `class`s. - -```csharp -enum Unit -{ - Kg, - Lb -} - -struct Weight -{ - private double count; - private Unit unit; - - public Weight(double count, Unit unit) - { - this.count = count; - this.unit = unit; - } - - public override string ToString() - { - return count.ToString() + unit.ToString(); - } -} - -new Weight(77.5, Unit.Kg).ToString(); -// => "77.6Kg" -``` - -One of the main things to remember is that when one struct is assigned to a variable or passed as a parameter the values are copied across so changes to the original variable will not affect the copied one and vice versa. In summary, `struct`s are **value types**. - -This [article][class-or-struct] discusses the differences between `struct`s and `class`s. You will see from the article that `struct`s tend to be lightweight and [immutable][structs-immutable] although this guidance is not enforced (by default) by the compiler or runtime. - -There are a couple of things that you will come up against (and about which the compiler will remind you): - -1. Members of a `struct` cannot be initialized inline. -2. A `struct` cannot be inherited -3. A `struct` always has a default constructor even if a non-default one is provided, and you cannot provide an explicit parameterless constructor. - -As a result of points 1 and 3 above there is no way for the developer of a `struct` to prevent invalid instances from coming into existence. - -#### Common structs - -You will see from the documentation that there is a close relationship between primitives and structs. See [`Int32/int]`][int32], for an example. A more conventional example of a`struct`is the type [`TimeSpan`][time-span]. - -Instances of `TimeSpan` behave much like numbers with comparison operators like `>` and `<` and arithmetic operators. You can implement these operators for your own `struct`s when you need them. - -One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable`. Although `struct`s cannot be derived from other `struct`s they can implement interfaces. - -#### Equality - -Equality testing for `struct`s can often be much simpler than that for `class`s as it simply compares fields for equality by default. There is no need to override `object.Equals()` (or `GetHashCode()`). Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use. Effectively, this means that structs used in this way should be immutable. See (TODO cross-ref-tba). - -In contrast to the method, `Equals()`, there is no default implementation of the equality operators, `==` and `!=`. If your `struct` needs them then you will have to implement them. - -On the other hand, this [article][equality] describes how performance can be optimised by creating your own custom `Equals()` and `GetHashCode()` method as is often done with `class`s. The difference in the case of this exercise was about 20% in a not very rigorous comparison but that may be on the low side because all the fields are of the same type - see below. - -There are discussions on the [web][equality-performance] about speed improvements, where the `Equals()` method is not overridden, if all fields are of the same type. The difference in this exercise of including disparate fields was about 60%. This is not mentioned in Microsoft's documentation so that makes it an un-documented implementation detail, and it should be exploited judiciously. - -```csharp -public bool Equals(Weight other) -{ - return count.Equals(other.count) && unit.Equals(other.unit); -} - -public override bool Equals(object obj) -{ - return obj is Weight other && Equals(other); -} - -public override int GetHashCode() -{ - return HashCode.Combine(count, unit); -} -``` - -#### General - -- [structs][structs]: introduction to structs. -- [class-or-struct][class-or-struct]: lists the guidelines for choosing between a struct and class. - -[structs-immutable]: https://stackoverflow.com/a/3753640/96167 -[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 -[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading -[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type -[equality-performance]: https://medium.com/@semuserable/c-journey-into-struct-equality-comparison-deep-dive-9693f74562f1 -[structs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct -[class-or-struct]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/choosing-between-class-and-struct -[int32]: https://docs.microsoft.com/en-us/dotnet/api/system.int32?view=netcore-3.1 -[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-3.1 From 706f3f5d7689a3d9f3866ea66c35caac97e93dde Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 15:41:42 +0200 Subject: [PATCH 214/327] strings - replace about.md file with concept files * Pre-populate strings concept's about.md file from after.md file * Pre-populate strings concept's links.json file from after.md file * strings - Remove after.md document --- concepts/strings/about.md | 41 +++++++++++++++++++++++- concepts/strings/links.json | 31 +++++++++++++++++- exercises/concept/strings/.docs/after.md | 40 ----------------------- 3 files changed, 70 insertions(+), 42 deletions(-) delete mode 100644 exercises/concept/strings/.docs/after.md diff --git a/concepts/strings/about.md b/concepts/strings/about.md index b046260477..92a7332bef 100644 --- a/concepts/strings/about.md +++ b/concepts/strings/about.md @@ -1 +1,40 @@ -TODO: add information on strings concept +The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance: + +```csharp +string fruit = "Apple"; +``` + +Manipulating a string can be done by calling one of its [methods][methods] or [properties][properties]. As string values can never change after having been defined, all string manipulation methods will return a new string. + +A string is delimited by double quote (`"`) characters. Some special characters need [escaping][escaping] using the backslash (`\`) character. Strings can also be prefixed with the at (`@`) symbol, which makes it a [verbatim string][verbatim] that will ignore any escaped characters. + +```csharp +string escaped = "c:\\test.txt"; +string verbatim = @"c:\test.txt"; +escaped == verbatim; +// => true +``` + +Finally, there are [many ways to concatenate a string][concatenation]. The simplest one is by using the [`+` operator][plus-operator]. + +```csharp +string name = "Jane"; +"Hello " + name + "!"; +// => "Hello Jane!" +``` + +For any string formatting more complex than simple concatenation, [string interpolation][interpolation] is preferred. To enable interpolation in a string, prefix it with the dollar (`$`) symbol. + +```csharp +string name = "Jane"; +$"Hello {name}!"; +// => "Hello Jane!" +``` + +[concatenation]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings +[interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +[verbatim]: https://csharp.net-tutorials.com/data-types/strings/#aelm5298 +[plus-operator]: https://csharp.net-tutorials.com/data-types/strings/#aelm5211 +[escaping]: https://devblogs.microsoft.com/csharpfaq/what-character-escape-sequences-are-available/ +[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#methods +[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#properties diff --git a/concepts/strings/links.json b/concepts/strings/links.json index fe51488c70..4a0b513ef1 100644 --- a/concepts/strings/links.json +++ b/concepts/strings/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#methods", + "description": "methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#properties", + "description": "properties" + }, + { + "url": "https://devblogs.microsoft.com/csharpfaq/what-character-escape-sequences-are-available/", + "description": "escaping" + }, + { + "url": "https://csharp.net-tutorials.com/data-types/strings/#aelm5298", + "description": "verbatim" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings", + "description": "concatenation" + }, + { + "url": "https://csharp.net-tutorials.com/data-types/strings/#aelm5211", + "description": "plus-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation", + "description": "interpolation" + } +] diff --git a/exercises/concept/strings/.docs/after.md b/exercises/concept/strings/.docs/after.md deleted file mode 100644 index 92a7332bef..0000000000 --- a/exercises/concept/strings/.docs/after.md +++ /dev/null @@ -1,40 +0,0 @@ -The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance: - -```csharp -string fruit = "Apple"; -``` - -Manipulating a string can be done by calling one of its [methods][methods] or [properties][properties]. As string values can never change after having been defined, all string manipulation methods will return a new string. - -A string is delimited by double quote (`"`) characters. Some special characters need [escaping][escaping] using the backslash (`\`) character. Strings can also be prefixed with the at (`@`) symbol, which makes it a [verbatim string][verbatim] that will ignore any escaped characters. - -```csharp -string escaped = "c:\\test.txt"; -string verbatim = @"c:\test.txt"; -escaped == verbatim; -// => true -``` - -Finally, there are [many ways to concatenate a string][concatenation]. The simplest one is by using the [`+` operator][plus-operator]. - -```csharp -string name = "Jane"; -"Hello " + name + "!"; -// => "Hello Jane!" -``` - -For any string formatting more complex than simple concatenation, [string interpolation][interpolation] is preferred. To enable interpolation in a string, prefix it with the dollar (`$`) symbol. - -```csharp -string name = "Jane"; -$"Hello {name}!"; -// => "Hello Jane!" -``` - -[concatenation]: https://docs.microsoft.com/en-us/dotnet/csharp/how-to/concatenate-multiple-strings -[interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation -[verbatim]: https://csharp.net-tutorials.com/data-types/strings/#aelm5298 -[plus-operator]: https://csharp.net-tutorials.com/data-types/strings/#aelm5211 -[escaping]: https://devblogs.microsoft.com/csharpfaq/what-character-escape-sequences-are-available/ -[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#methods -[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.string?view=netcore-3.1#properties From 27c8fa21eaee2678637cd8acd34b6f91deef2b88 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 15:59:41 +0200 Subject: [PATCH 215/327] user-defined-exceptions - replace about.md file with concept files * Pre-populate user-defined-exceptions concept's about.md file from after.md file * Pre-populate user-defined-exceptions concept's links.json file from after.md file * Pre-populate exception-filtering concept's about.md file from after.md file * Pre-populate exception-filtering concept's links.json file from after.md file * user-defined-exceptions - Remove after.md document split concepts in about.md * Update about.md * Update links.json * Update links.json Co-authored-by: mikedamay --- concepts/exception-filtering/about.md | 23 ++++++++- concepts/exception-filtering/links.json | 7 ++- concepts/user-defined-exceptions/about.md | 28 ++++++++++- concepts/user-defined-exceptions/links.json | 19 ++++++- .../user-defined-exceptions/.docs/after.md | 50 ------------------- 5 files changed, 73 insertions(+), 54 deletions(-) delete mode 100644 exercises/concept/user-defined-exceptions/.docs/after.md diff --git a/concepts/exception-filtering/about.md b/concepts/exception-filtering/about.md index 215d1cbb62..cabc830e18 100644 --- a/concepts/exception-filtering/about.md +++ b/concepts/exception-filtering/about.md @@ -1 +1,22 @@ -TODO: add information on exception-filtering concept +TODO: This may need a more rounded introduction to filtering here. +`when` is the keyword in filtering exceptions. It is placed after the catch +statement and can take a boolean expression containing any values in scope at the time. They don't just have to be members of the exception itself. If the type of the exception matches and the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked. + +```csharp +try +{ + // do stuff +} +catch (Exception ex) when (ex.Message != "") +{ + // output the message when it is not empty +} +catch (Exception ex) +{ + // show stack trace or something. +} +``` + +- This [Exception filters][exception-filters] article shows how to filter exceptions. + +[exception-filters]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/when diff --git a/concepts/exception-filtering/links.json b/concepts/exception-filtering/links.json index fe51488c70..32a0d5c159 100644 --- a/concepts/exception-filtering/links.json +++ b/concepts/exception-filtering/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/when", + "description": "exception-filters" + } +] diff --git a/concepts/user-defined-exceptions/about.md b/concepts/user-defined-exceptions/about.md index 107b3955ef..c9a02dcec2 100644 --- a/concepts/user-defined-exceptions/about.md +++ b/concepts/user-defined-exceptions/about.md @@ -1 +1,27 @@ -TODO: add information on user-defined-exceptions concept +A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. User-defined exceptions can be used in every way like runtime and Microsoft Base Class Library exceptions. + +This special treatment applies only to `Exception`-derived classes. You cannot throw instances of any other type. + +User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines. This can then be recorded in logs, reported to a user or perhaps used in a retry operation. `System.Exception` has convenient data members and appropriate constructors to hold a message and the "inner" exception. + +By convention exception class names end with "Exception", e.g. `MyTerribleException`. + +Whilst using user-defined exceptions to wrap and enhance third party exceptions is a frequently seen pattern, the general advice is not to use them outside of this use case too liberally in your own code. It is considered an anti-pattern. There are challenges to this view and you can see both sides of the argument in this [Stack Exchange post][se-exceptions]. + +This [article][create-user-defined-exceptions] is a good introduction to user-defined exceptions. + +As part of their guidance on [creating and throwing exceptions][exceptions-guidance] the .NET team recommend that user defined exceptions have a number of [convenience constructors][convenience-constructors]. For most purposes the combination illustrated below is appropriate. + +```csharp +public class IncompleteExerciseException : System.Exception +{ + public IncompleteExerciseException() : base() { } + public IncompleteExerciseException(string message) : base(message) { } + public IncompleteExerciseException(string message, System.Exception inner) : base(message, inner) { } +} +``` + +[create-user-defined-exceptions]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions +[se-exceptions]: https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why +[exceptions-guidance]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions +[convenience-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions#defining-exception-classes diff --git a/concepts/user-defined-exceptions/links.json b/concepts/user-defined-exceptions/links.json index fe51488c70..65e7f37a99 100644 --- a/concepts/user-defined-exceptions/links.json +++ b/concepts/user-defined-exceptions/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why", + "description": "se-exceptions" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions", + "description": "create-user-defined-exceptions" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions", + "description": "exceptions-guidance" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions#defining-exception-classes", + "description": "convenience-constructors" + } +] diff --git a/exercises/concept/user-defined-exceptions/.docs/after.md b/exercises/concept/user-defined-exceptions/.docs/after.md deleted file mode 100644 index 841351f175..0000000000 --- a/exercises/concept/user-defined-exceptions/.docs/after.md +++ /dev/null @@ -1,50 +0,0 @@ -A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. User-defined exceptions can be used in every way like runtime and Microsoft Base Class Library exceptions. - -This special treatment applies only to `Exception`-derived classes. You cannot throw instances of any other type. - -User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines. This can then be recorded in logs, reported to a user or perhaps used in a retry operation. `System.Exception` has convenient data members and appropriate constructors to hold a message and the "inner" exception. - -By convention exception class names end with "Exception", e.g. `MyTerribleException`. - -Whilst using user-defined exceptions to wrap and enhance third party exceptions is a frequently seen pattern, the general advice is not to use them outside of this use case too liberally in your own code. It is considered an anti-pattern. There are challenges to this view and you can see both sides of the argument in this [Stack Exchange post][se-exceptions]. - -This [article][create-user-defined-exceptions] is a good introduction to user-defined exceptions. - -As part of their guidance on [creating and throwing exceptions][exceptions-guidance] the .NET team recommend that user defined exceptions have a number of [convenience constructors][convenience-constructors]. For most purposes the combination illustrated below is appropriate. - -```csharp -public class IncompleteExerciseException : System.Exception -{ - public IncompleteExerciseException() : base() { } - public IncompleteExerciseException(string message) : base(message) { } - public IncompleteExerciseException(string message, System.Exception inner) : base(message, inner) { } -} -``` - -## Exception Filters - -`when` is the keyword in filtering exceptions. It is placed after the catch -statement and can take a boolean expression containing any values in scope at the time. They don't just have to be members of the exception itself. If the type of the exception matches and the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked. - -```csharp -try -{ - // do stuff -} -catch (Exception ex) when (ex.Message != "") -{ - // output the message when it is not empty -} -catch (Exception ex) -{ - // show stack trace or something. -} -``` - -- This [Exception filters][exception-filters] article shows how to filter exceptions. - -[create-user-defined-exceptions]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-create-user-defined-exceptions -[exception-filters]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/when -[se-exceptions]: https://softwareengineering.stackexchange.com/questions/189222/are-exceptions-as-control-flow-considered-a-serious-antipattern-if-so-why -[exceptions-guidance]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions -[convenience-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/exceptions/creating-and-throwing-exceptions#defining-exception-classes From 40eb6c229279127da596f887d8cc7b88875c64c1 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 16:02:20 +0200 Subject: [PATCH 216/327] time - replace about.md file with concept files * Pre-populate time concept's about.md file from after.md file * Pre-populate time concept's links.json file from after.md file * Pre-populate timezone concept's about.md file from after.md file * Pre-populate timezone concept's links.json file from after.md file * time - Remove after.md document * Update about.md * Update links.json * Update links.json * Update about.md * Update links.json * [CI] Format code Co-authored-by: Mike May Co-authored-by: github-actions[bot] --- concepts/time/about.md | 43 +++++++++++++++++++++++++- concepts/time/links.json | 32 ++++++++++++++++++- concepts/timezone/links.json | 11 ++++++- exercises/concept/time/.docs/after.md | 44 --------------------------- 4 files changed, 83 insertions(+), 47 deletions(-) delete mode 100644 exercises/concept/time/.docs/after.md diff --git a/concepts/time/about.md b/concepts/time/about.md index 5c95b2bfc4..1e1a85a43c 100644 --- a/concepts/time/about.md +++ b/concepts/time/about.md @@ -1 +1,42 @@ -TODO: add information on time concept +Although this exercise investigates the concept of `time` in practice you rarely deal with times on their own. They are almost always dealt with in conjunction with dates. There is no specific separate _time_ type, only [`DateTime`][date-time]. + +Time-of-day can be expressed with [`TimeSpan`][time-span] (and this is in fact the return type of `DateTime.TimeOfDay`). It is not [purpose made][skeet-time-of-day] so the expressiveness of code can get a bit clunky. For instance, what do you expect time-of-day to be for an instance of `DateTime` that is in UTC form? But, it does the job. + +A discussion of _time_ has a number of facets: + +- local time vs. universal co-ordinated time (UTC) +- arithmetic on `DateTime` +- Time zones (including daylight saving time) +- Date-time string parsing and formatting. +- Resolution (timer selection etc.) + +This exercise covered local vs. UTC, date-time arithmetic, time-zones and date-time parsing. + +[Formatting][date-string-formatting] is discussed in the `string-formatting` exercise. + +Resolution and timers are [much discussed][so-timers] on the web. The `DateTime` API has specific routines to handle file timestamps. + +It's usually a good idea to store date-times long term in UTC form. This ensures consistency if more than one timezone is in play and this approach avoids potential problems with daylight saving. + +The disadvantage of UTC times is that they need to be converted to local times if time-of-day is a significant factor. + +For the most part `DateTime.ToUniversalTime()` and `DateTime.ToLocalTime()` work well as long as processing is based around the timezone of your computer. If multiple time zones are involved, or a different one to that of your computer then you will need the [`TimeZoneInfo`][time-zone-info] class to handle conversions. Not the obsolete ~~TimeZone~~ object. + +You will recall from the coding exercise that the all-important time zone identifiers differ between Windows and other platforms. This [article][cross-platform-time-zones] is a good introduction to this cross-platform issue. Note that `TimeZoneInfo.GetSystemTimeZones()` will list your platform's time zones. + +This [article][time-overview] is a good overview of time and timezones. + +For date time arithmetic, in the coding exercise, you may well have used the `TimeSpan` struct. When you need to do arithmetic involving whole months or years then the `DateTime` struct provides a number of methods such as `AddHours()` and `AddMonths()`. + +If dates and times are a pervasive and/or critical part of your project then you should investigate [Noda Time][noda-time] + +In case you were wondering, according to this [Wikipedia article][wiki-utc] the abbreviation for universal time, UTC, arose from a compromise between English (UCT) and French (CUT) speakers such that neither language would appear to take precedence. + +[so-timers]: https://stackoverflow.com/questions/10317088/why-there-are-5-versions-of-timer-classes-in-net +[skeet-time-of-day]: https://stackoverflow.com/a/2037375/96167 +[time-overview]: https://docs.microsoft.com/en-us/dotnet/standard/datetime/ +[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 +[noda-time]: https://nodatime.org/ +[date-string-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-2.0 +[wiki-utc]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time diff --git a/concepts/time/links.json b/concepts/time/links.json index fe51488c70..b6994f30e1 100644 --- a/concepts/time/links.json +++ b/concepts/time/links.json @@ -1 +1,31 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1", + "description": "date-time" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-2.0", + "description": "time-span" + }, + { + "url": "https://stackoverflow.com/a/2037375/96167", + "description": "skeet-time-of-day" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings", + "description": "date-string-formatting" + }, + { + "url": "https://stackoverflow.com/questions/10317088/why-there-are-5-versions-of-timer-classes-in-net", + "description": "so-timers" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/datetime/", + "description": "time-overview" + }, + { "url": "https://nodatime.org/", "description": "noda-time" }, + { + "url": "https://en.wikipedia.org/wiki/Coordinated_Universal_Time", + "description": "wiki-utc" + } +] diff --git a/concepts/timezone/links.json b/concepts/timezone/links.json index fe51488c70..4d9d92c701 100644 --- a/concepts/timezone/links.json +++ b/concepts/timezone/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=netcore-2.0", + "description": "time-zone-info" + }, + { + "url": "https://devblogs.microsoft.com/dotnet/cross-platform-time-zones-with-net-core/", + "description": "cross-platform-time-zones" + } +] diff --git a/exercises/concept/time/.docs/after.md b/exercises/concept/time/.docs/after.md deleted file mode 100644 index a4fd522383..0000000000 --- a/exercises/concept/time/.docs/after.md +++ /dev/null @@ -1,44 +0,0 @@ -Although this exercise investigates the concept of `time` in practice you rarely deal with times on their own. They are almost always dealt with in conjunction with dates. There is no specific separate _time_ type, only [`DateTime`][date-time]. - -Time-of-day can be expressed with [`TimeSpan`][time-span] (and this is in fact the return type of `DateTime.TimeOfDay`). It is not [purpose made][skeet-time-of-day] so the expressiveness of code can get a bit clunky. For instance, what do you expect time-of-day to be for an instance of `DateTime` that is in UTC form? But, it does the job. - -A discussion of _time_ has a number of facets: - -- local time vs. universal co-ordinated time (UTC) -- arithmetic on `DateTime` -- Time zones (including daylight saving time) -- Date-time string parsing and formatting. -- Resolution (timer selection etc.) - -This exercise covered local vs. UTC, date-time arithmetic, time-zones and date-time parsing. - -[Formatting][date-string-formatting] is discussed in the `string-formatting` exercise. - -Resolution and timers are [much discussed][so-timers] on the web. The `DateTime` API has specific routines to handle file timestamps. - -It's usually a good idea to store date-times long term in UTC form. This ensures consistency if more than one timezone is in play and this approach avoids potential problems with daylight saving. - -The disadvantage of UTC times is that they need to be converted to local times if time-of-day is a significant factor. - -For the most part `DateTime.ToUniversalTime()` and `DateTime.ToLocalTime()` work well as long as processing is based around the timezone of your computer. If multiple time zones are involved, or a different one to that of your computer then you will need the [`TimeZoneInfo`][time-zone-info] class to handle conversions. Not the obsolete ~~TimeZone~~ object. - -You will recall from the coding exercise that the all-important time zone identifiers differ between Windows and other platforms. This [article][cross-platform-time-zones] is a good introduction to this cross-platform issue. Note that `TimeZoneInfo.GetSystemTimeZones()` will list your platform's time zones. - -This [article][time-overview] is a good overview of time and timezones. - -For date time arithmetic, in the coding exercise, you may well have used the `TimeSpan` struct. When you need to do arithmetic involving whole months or years then the `DateTime` struct provides a number of methods such as `AddHours()` and `AddMonths()`. - -If dates and times are a pervasive and/or critical part of your project then you should investigate [Noda Time][noda-time] - -In case you were wondering, according to this [Wikipedia article][wiki-utc] the abbreviation for universal time, UTC, arose from a compromise between English (UCT) and French (CUT) speakers such that neither language would appear to take precedence. - -[so-timers]: https://stackoverflow.com/questions/10317088/why-there-are-5-versions-of-timer-classes-in-net -[cross-platform-time-zones]: https://devblogs.microsoft.com/dotnet/cross-platform-time-zones-with-net-core/ -[skeet-time-of-day]: https://stackoverflow.com/a/2037375/96167 -[time-overview]: https://docs.microsoft.com/en-us/dotnet/standard/datetime/ -[date-time]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1 -[noda-time]: https://nodatime.org/ -[date-string-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings -[time-span]: https://docs.microsoft.com/en-us/dotnet/api/system.timespan?view=netcore-2.0 -[time-zone-info]: https://docs.microsoft.com/en-us/dotnet/api/system.timezoneinfo?view=netcore-2.0 -[wiki-utc]: https://en.wikipedia.org/wiki/Coordinated_Universal_Time From 6cbc81ce2d94ec333aa0362f4bb415b2e6c83877 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 21 Oct 2020 16:08:17 +0200 Subject: [PATCH 217/327] resource-lifetime - replace about.md file with concept files * Pre-populate resource-lifetime concept's about.md file from after.md file * Pre-populate resource-lifetime concept's links.json file from after.md file * resource-lifetime - Remove after.md document --- concepts/resource-lifetime/about.md | 78 ++++++++++++++++++- concepts/resource-lifetime/links.json | 23 +++++- .../concept/resource-lifetime/.docs/after.md | 77 ------------------ 3 files changed, 99 insertions(+), 79 deletions(-) delete mode 100644 exercises/concept/resource-lifetime/.docs/after.md diff --git a/concepts/resource-lifetime/about.md b/concepts/resource-lifetime/about.md index 452f7b049a..6b029325c0 100644 --- a/concepts/resource-lifetime/about.md +++ b/concepts/resource-lifetime/about.md @@ -1 +1,77 @@ -TODO: add information on resource-lifetime concept +We discussed in (TODO cross-ref-tba) how the `IDispoable` interface helps signal to callers of a class that there are resources or program state that need releasing or resetting in a timely fashion when the object in question is no longer required. In this exercise we have introduced some syntactic sugar, with the `using` keyword, that makes the code less verbose and less likely that significant calls will be omitted. + +`using` can be seen as replacing [`try/finally`][try-finally] for some use cases. + +```csharp +File file = null; +try +{ + file = new File("myStuff.txt"); + file.Write("more stuff"); +} +finally +{ + file.Dispose(); +} +``` + +This syntax is replaced with the more compact and foolproof: + +```csharp +using (var file = new File("myStuff.txt") +{ + file.Write("more stuff"); +} +``` + +Note that multiple resources can be conveniently combined following standard rules for single line blocks: + +```csharp +using (var file = new File("mystuff.txt") +using (var fileWriter = new StreamWriter(file) +{ + ... +} +``` + +In C# 8 the following variation has been introduced where the `using` statement comes at the start of a block: + +```csharp +using var file = new File("myStuff.txt"); +file.Write("more stuff"); +``` + +This allows you to have multiple disposable objects in the same block and to more naturally handle [`try/catch`][try-catch]: + +```csharp +using var fileIn = new File("myStuff.txt"); +using var fileOut = new File("yourStuff.txt"); +try +{ + var stuff = fileIn.Read(); + fileOut.Write(stuff); +} +catch (Exception) +{ + LogStuff(); +} +``` + +The rules related to how the `using` keyword can be used and with instances of what sort of types are detailed [here][using-statement]. + +#### Note for Java Developers + +Java developers may recognize this as an analog of the [_automatic resource management_][automatic-resource-management] mechanism introduced in Java 7. They are very similar. Java's syntax, which repurposes `try` has the advantage of incorporating `catch` blocks more naturally than does C#'s `using`. + +#### Versions + +Note that the more flexible version of `using` where it does not have its own syntactic block was introduced in C# 8 so you may need to check if the code base you are working on is using C# 8 or later. + +#### Reference + +[using statement][using-statement] documentation describes how and when to use the `using` keyword. + +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[automatic-resource-management]: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html +[try-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally +[try-catch]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-the-try-catch-block-to-catch-exceptions diff --git a/concepts/resource-lifetime/links.json b/concepts/resource-lifetime/links.json index fe51488c70..704a1665e8 100644 --- a/concepts/resource-lifetime/links.json +++ b/concepts/resource-lifetime/links.json @@ -1 +1,22 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally", + "description": "try-finally" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-the-try-catch-block-to-catch-exceptions", + "description": "try-catch" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement", + "description": "using-statement" + }, + { + "url": "https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html", + "description": "automatic-resource-management" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement", + "description": "using-statement" + } +] diff --git a/exercises/concept/resource-lifetime/.docs/after.md b/exercises/concept/resource-lifetime/.docs/after.md deleted file mode 100644 index 6b029325c0..0000000000 --- a/exercises/concept/resource-lifetime/.docs/after.md +++ /dev/null @@ -1,77 +0,0 @@ -We discussed in (TODO cross-ref-tba) how the `IDispoable` interface helps signal to callers of a class that there are resources or program state that need releasing or resetting in a timely fashion when the object in question is no longer required. In this exercise we have introduced some syntactic sugar, with the `using` keyword, that makes the code less verbose and less likely that significant calls will be omitted. - -`using` can be seen as replacing [`try/finally`][try-finally] for some use cases. - -```csharp -File file = null; -try -{ - file = new File("myStuff.txt"); - file.Write("more stuff"); -} -finally -{ - file.Dispose(); -} -``` - -This syntax is replaced with the more compact and foolproof: - -```csharp -using (var file = new File("myStuff.txt") -{ - file.Write("more stuff"); -} -``` - -Note that multiple resources can be conveniently combined following standard rules for single line blocks: - -```csharp -using (var file = new File("mystuff.txt") -using (var fileWriter = new StreamWriter(file) -{ - ... -} -``` - -In C# 8 the following variation has been introduced where the `using` statement comes at the start of a block: - -```csharp -using var file = new File("myStuff.txt"); -file.Write("more stuff"); -``` - -This allows you to have multiple disposable objects in the same block and to more naturally handle [`try/catch`][try-catch]: - -```csharp -using var fileIn = new File("myStuff.txt"); -using var fileOut = new File("yourStuff.txt"); -try -{ - var stuff = fileIn.Read(); - fileOut.Write(stuff); -} -catch (Exception) -{ - LogStuff(); -} -``` - -The rules related to how the `using` keyword can be used and with instances of what sort of types are detailed [here][using-statement]. - -#### Note for Java Developers - -Java developers may recognize this as an analog of the [_automatic resource management_][automatic-resource-management] mechanism introduced in Java 7. They are very similar. Java's syntax, which repurposes `try` has the advantage of incorporating `catch` blocks more naturally than does C#'s `using`. - -#### Versions - -Note that the more flexible version of `using` where it does not have its own syntactic block was introduced in C# 8 so you may need to check if the code base you are working on is using C# 8 or later. - -#### Reference - -[using statement][using-statement] documentation describes how and when to use the `using` keyword. - -[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement -[automatic-resource-management]: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html -[try-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-finally -[try-catch]: https://docs.microsoft.com/en-us/dotnet/standard/exceptions/how-to-use-the-try-catch-block-to-catch-exceptions From fd4d22edc08d5a713f37fd611888d12125956e15 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:35:25 +0200 Subject: [PATCH 218/327] resource-cleanup - replace about.md file with concept files * Pre-populate resource-cleanup concept's about.md file from after.md file * Pre-populate resource-cleanup concept's links.json file from after.md file * resource-cleanup - Remove after.md document --- concepts/resource-cleanup/about.md | 71 ++++++++++++++++++- concepts/resource-cleanup/links.json | 43 ++++++++++- .../concept/resource-cleanup/.docs/after.md | 70 ------------------ 3 files changed, 112 insertions(+), 72 deletions(-) delete mode 100644 exercises/concept/resource-cleanup/.docs/after.md diff --git a/concepts/resource-cleanup/about.md b/concepts/resource-cleanup/about.md index 8dfc2b5f55..a1ed529cce 100644 --- a/concepts/resource-cleanup/about.md +++ b/concepts/resource-cleanup/about.md @@ -1 +1,70 @@ -TODO: add information on resource-cleanup concept +The [`IDisposable`][idisposable] interface is central to resource cleanup and has two significant roles in C#: + +- It indicates to users of the implementing class that they are responsible for letting the class know (by calling the [`Dispose()`][dispose] method) that it is no longer required so that it can release any unmanaged resources or reset its internal state as appropriate. This contrasts with the normal approach to cleaning up of allowing the [garbage collector][garbage-collector] to clean everything up (principally, release memory). +- In conjunction with the compiler and runtime the `IDisposable` interface supports the [`using` statement][using-statement] discussed in the `resource-lifetime` exercise. + +It is possible but unlikely that `Dispose()` will be called through the interface in some sort of generic cleanup routine. + +`IDisposable` is most commonly encountered with library classes that wrap operating system (unmanaged) resources such as [`System.IO.Stream`][stream] and [`System.IO.TextReader`][text-reader]. (`Stream`s and `TextReader`s are covered in other exercises). + +```csharp +public class TextHandler : IDispoable +{ + private TextReader reader = new TextReader(...); + + public void Dispose() + { + reader.Dispose(); + } +} +``` + +If a class you are using implements the `IDispoable` interface then you must ensure that `Dispose()` is called (by use of [`catch` and `finally`][try-catch-finally] clauses) when the instance is no longer required. If a class has a member which implements `IDisposable` then it may well need to implement `IDisposable` itself so that `Dispose()` can be called to dispose of the `IDisposble`-implementing member. + +```csharp +public class Activity : IDisposable +{ + private MyResource myResource; + + public Activity() + { + myResource = new MyResource(); + } + + public void Perform() + { + try + { + myResource.BeUseful(); + } + catch (Exception) + { + myResource.Dispose(); + } + } + + public void Dispose() + { + myResource.Dispose(); + } +} +``` + +The `IDisposable` interface may be useful even where no unmanaged resources are in the mix. Say you have a long-lived object which requires short-lived objects to register themselves with it and then unregister when they are no longer required. Implementing `IDisposable` on the short-lived object puts a developer using that class on notice that `Dispose()` needs to be called at the end of the short-lived object's life. + +#### Dispose pattern + +You will see references in the documentation to the [dispose pattern][dispose-pattern]. The _dispose pattern_ includes calling `Dispose()` from a class's [finalizer][finalizer] and ensuring that disposal of resources in base classes is handled correctly. The _dispose pattern_ is dealt with in a later exercise. + +The _dispose pattern_ mostly relates to unmanaged resources. If you are using [P/Inovke mechanism][native-interoperability] and `extern` methods then you need to understand how and when to implement the dispose pattern. Most C# developers rarely have to deal directly with unmanaged resources in this way. + +[finalizer]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors +[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement +[idisposable]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netcore-3.1 +[dispose]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?view=netcore-3.1 +[stream]: https://docs.microsoft.com/en-us/dotnet/api/system.io.stream?view=netcore-3.1 +[text-reader]: https://docs.microsoft.com/en-us/dotnet/api/system.io.textreader?view=netcore-3.1 +[native-interoperability]: https://docs.microsoft.com/en-us/dotnet/standard/native-interop/ +[dispose-pattern]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose +[garbage-collector]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals +[try-catch-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch-finally diff --git a/concepts/resource-cleanup/links.json b/concepts/resource-cleanup/links.json index fe51488c70..e8d8c6ad5b 100644 --- a/concepts/resource-cleanup/links.json +++ b/concepts/resource-cleanup/links.json @@ -1 +1,42 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netcore-3.1", + "description": "idisposable" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?view=netcore-3.1", + "description": "dispose" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals", + "description": "garbage-collector" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement", + "description": "using-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.io.stream?view=netcore-3.1", + "description": "stream" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.io.textreader?view=netcore-3.1", + "description": "text-reader" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch-finally", + "description": "try-catch-finally" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose", + "description": "dispose-pattern" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors", + "description": "finalizer" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/native-interop/", + "description": "native-interoperability" + } +] diff --git a/exercises/concept/resource-cleanup/.docs/after.md b/exercises/concept/resource-cleanup/.docs/after.md deleted file mode 100644 index a1ed529cce..0000000000 --- a/exercises/concept/resource-cleanup/.docs/after.md +++ /dev/null @@ -1,70 +0,0 @@ -The [`IDisposable`][idisposable] interface is central to resource cleanup and has two significant roles in C#: - -- It indicates to users of the implementing class that they are responsible for letting the class know (by calling the [`Dispose()`][dispose] method) that it is no longer required so that it can release any unmanaged resources or reset its internal state as appropriate. This contrasts with the normal approach to cleaning up of allowing the [garbage collector][garbage-collector] to clean everything up (principally, release memory). -- In conjunction with the compiler and runtime the `IDisposable` interface supports the [`using` statement][using-statement] discussed in the `resource-lifetime` exercise. - -It is possible but unlikely that `Dispose()` will be called through the interface in some sort of generic cleanup routine. - -`IDisposable` is most commonly encountered with library classes that wrap operating system (unmanaged) resources such as [`System.IO.Stream`][stream] and [`System.IO.TextReader`][text-reader]. (`Stream`s and `TextReader`s are covered in other exercises). - -```csharp -public class TextHandler : IDispoable -{ - private TextReader reader = new TextReader(...); - - public void Dispose() - { - reader.Dispose(); - } -} -``` - -If a class you are using implements the `IDispoable` interface then you must ensure that `Dispose()` is called (by use of [`catch` and `finally`][try-catch-finally] clauses) when the instance is no longer required. If a class has a member which implements `IDisposable` then it may well need to implement `IDisposable` itself so that `Dispose()` can be called to dispose of the `IDisposble`-implementing member. - -```csharp -public class Activity : IDisposable -{ - private MyResource myResource; - - public Activity() - { - myResource = new MyResource(); - } - - public void Perform() - { - try - { - myResource.BeUseful(); - } - catch (Exception) - { - myResource.Dispose(); - } - } - - public void Dispose() - { - myResource.Dispose(); - } -} -``` - -The `IDisposable` interface may be useful even where no unmanaged resources are in the mix. Say you have a long-lived object which requires short-lived objects to register themselves with it and then unregister when they are no longer required. Implementing `IDisposable` on the short-lived object puts a developer using that class on notice that `Dispose()` needs to be called at the end of the short-lived object's life. - -#### Dispose pattern - -You will see references in the documentation to the [dispose pattern][dispose-pattern]. The _dispose pattern_ includes calling `Dispose()` from a class's [finalizer][finalizer] and ensuring that disposal of resources in base classes is handled correctly. The _dispose pattern_ is dealt with in a later exercise. - -The _dispose pattern_ mostly relates to unmanaged resources. If you are using [P/Inovke mechanism][native-interoperability] and `extern` methods then you need to understand how and when to implement the dispose pattern. Most C# developers rarely have to deal directly with unmanaged resources in this way. - -[finalizer]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/destructors -[using-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement -[idisposable]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable?view=netcore-3.1 -[dispose]: https://docs.microsoft.com/en-us/dotnet/api/system.idisposable.dispose?view=netcore-3.1 -[stream]: https://docs.microsoft.com/en-us/dotnet/api/system.io.stream?view=netcore-3.1 -[text-reader]: https://docs.microsoft.com/en-us/dotnet/api/system.io.textreader?view=netcore-3.1 -[native-interoperability]: https://docs.microsoft.com/en-us/dotnet/standard/native-interop/ -[dispose-pattern]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/implementing-dispose -[garbage-collector]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals -[try-catch-finally]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch-finally From 7a78726011a660ef92fbf9cfd3a39184ccdfcfd0 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:38:47 +0200 Subject: [PATCH 219/327] randomness - replace about.md file with concept files * Pre-populate randomness concept's about.md file from after.md file * Pre-populate randomness concept's links.json file from after.md file * randomness - Remove after.md document --- concepts/randomness/about.md | 43 ++++++++++++++++++- concepts/randomness/links.json | 47 ++++++++++++++++++++- exercises/concept/randomness/.docs/after.md | 42 ------------------ 3 files changed, 88 insertions(+), 44 deletions(-) delete mode 100644 exercises/concept/randomness/.docs/after.md diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md index 5695c7a266..9257c2c3a3 100644 --- a/concepts/randomness/about.md +++ b/concepts/randomness/about.md @@ -1 +1,42 @@ -TODO: add information on randomness concept +In C# applications randomness is generally implemented using the `System.Random` class. + +This [article][system-random] is an excellent introduction to the subject. + +When becoming familiar with a library class it is always worth studying the [documentation][system-random] for properties and methods and their overloads. + +The coding exercise highlighted a number of issues: + +- The random number generator does not require a [seed][random-seedless]. +- `Random.Next()` can generate a range of integers +- `Random.Double()` can generate a double between 0 and 1 +- The upper bounds in `Next...()`, `Double()` and `Sample()` are **exclusive** so that `Random.Next(1,19)` will yield values from 1 to 18 but not 19. +- Once you have your random number you can do what you like with it + +There are 3 patterns for implementing the last point: + +- You can get the random number and manipulate it. In the case of the coding exercise this would consist of calling `Random.NextDouble()` and multiplying by 100. This [piece][random-use-case-array] discusses making random selections from an array. +- You can inherit from `System.Random` and override the `Sampple()` method. +- You can encapsulate an instance of `System.Random` as a member of a class of your own, for example [to generate booleans][random-use-cases]. + +The numbers generated by `Random` are not guaranteed to be unique. + +It is [recommended][random-thread-safety] that you instantiate `System.Random` as a static member. But, note that it is not thread safe. + +You may see documentation discouraging the use of seedless constructors. This mostly applies to .NET Framework rather than .NET Core (which is what _Exercism_ uses). For the full story read [this][random-multiple-instantiations]. + +You are advised not to use `System.Random` for crypto or security. See this [provider][crypto-provider] and this [number generator][crypto-rng]. + +##### Thread safety + +When applied in the context of library APIs "not thread safe" is simply shorthand for saying that, if you are likely to access instances of the class through multiple concurrent [threads][threading], you should provide your own thread synchronization mechanisms or, in the case of collections, look at the possibility of using a concurrent version of the class. In the absence of these precautions, [race conditions][so-race-conditions] are likely to occur. If your code base does not use multiple threads, and is not likely to, then this warning is of little concern. + +[system-random]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1 +[random-thread-safety]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#the-systemrandom-class-and-thread-safety +[random-use-cases]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#generate-random-boolean-values +[random-use-case-array]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#UniqueArray +[crypto-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=netcore-3.1 +[crypto-rng]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=netcore-3.1 +[random-seedless]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#instantiating-the-random-number-generator +[random-multiple-instantiations]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#avoiding-multiple-instantiations +[so-race-conditions]: https://stackoverflow.com/questions/34510/what-is-a-race-condition +[threading]: https://docs.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading diff --git a/concepts/randomness/links.json b/concepts/randomness/links.json index fe51488c70..7c625aaf15 100644 --- a/concepts/randomness/links.json +++ b/concepts/randomness/links.json @@ -1 +1,46 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1", + "description": "system-random" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1", + "description": "system-random" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#instantiating-the-random-number-generator", + "description": "random-seedless" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#UniqueArray", + "description": "random-use-case-array" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#generate-random-boolean-values", + "description": "random-use-cases" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#the-systemrandom-class-and-thread-safety", + "description": "random-thread-safety" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#avoiding-multiple-instantiations", + "description": "random-multiple-instantiations" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=netcore-3.1", + "description": "crypto-provider" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=netcore-3.1", + "description": "crypto-rng" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading", + "description": "threading" + }, + { + "url": "https://stackoverflow.com/questions/34510/what-is-a-race-condition", + "description": "so-race-conditions" + } +] diff --git a/exercises/concept/randomness/.docs/after.md b/exercises/concept/randomness/.docs/after.md deleted file mode 100644 index 9257c2c3a3..0000000000 --- a/exercises/concept/randomness/.docs/after.md +++ /dev/null @@ -1,42 +0,0 @@ -In C# applications randomness is generally implemented using the `System.Random` class. - -This [article][system-random] is an excellent introduction to the subject. - -When becoming familiar with a library class it is always worth studying the [documentation][system-random] for properties and methods and their overloads. - -The coding exercise highlighted a number of issues: - -- The random number generator does not require a [seed][random-seedless]. -- `Random.Next()` can generate a range of integers -- `Random.Double()` can generate a double between 0 and 1 -- The upper bounds in `Next...()`, `Double()` and `Sample()` are **exclusive** so that `Random.Next(1,19)` will yield values from 1 to 18 but not 19. -- Once you have your random number you can do what you like with it - -There are 3 patterns for implementing the last point: - -- You can get the random number and manipulate it. In the case of the coding exercise this would consist of calling `Random.NextDouble()` and multiplying by 100. This [piece][random-use-case-array] discusses making random selections from an array. -- You can inherit from `System.Random` and override the `Sampple()` method. -- You can encapsulate an instance of `System.Random` as a member of a class of your own, for example [to generate booleans][random-use-cases]. - -The numbers generated by `Random` are not guaranteed to be unique. - -It is [recommended][random-thread-safety] that you instantiate `System.Random` as a static member. But, note that it is not thread safe. - -You may see documentation discouraging the use of seedless constructors. This mostly applies to .NET Framework rather than .NET Core (which is what _Exercism_ uses). For the full story read [this][random-multiple-instantiations]. - -You are advised not to use `System.Random` for crypto or security. See this [provider][crypto-provider] and this [number generator][crypto-rng]. - -##### Thread safety - -When applied in the context of library APIs "not thread safe" is simply shorthand for saying that, if you are likely to access instances of the class through multiple concurrent [threads][threading], you should provide your own thread synchronization mechanisms or, in the case of collections, look at the possibility of using a concurrent version of the class. In the absence of these precautions, [race conditions][so-race-conditions] are likely to occur. If your code base does not use multiple threads, and is not likely to, then this warning is of little concern. - -[system-random]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1 -[random-thread-safety]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#the-systemrandom-class-and-thread-safety -[random-use-cases]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#generate-random-boolean-values -[random-use-case-array]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#UniqueArray -[crypto-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.rngcryptoserviceprovider?view=netcore-3.1 -[crypto-rng]: https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.randomnumbergenerator?view=netcore-3.1 -[random-seedless]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#instantiating-the-random-number-generator -[random-multiple-instantiations]: https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-3.1#avoiding-multiple-instantiations -[so-race-conditions]: https://stackoverflow.com/questions/34510/what-is-a-race-condition -[threading]: https://docs.microsoft.com/en-us/dotnet/standard/threading/using-threads-and-threading From 7f88884a13b6b01140ed207a02e45723d84e1703 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:40:41 +0200 Subject: [PATCH 220/327] properties - replace about.md file with concept files * Pre-populate properties concept's about.md file from after.md file * properties - Remove after.md document --- concepts/properties/about.md | 81 ++++++++++++++++++++- exercises/concept/properties/.docs/after.md | 80 -------------------- 2 files changed, 80 insertions(+), 81 deletions(-) delete mode 100644 exercises/concept/properties/.docs/after.md diff --git a/concepts/properties/about.md b/concepts/properties/about.md index 6cbb8a7d5a..7882cf52a1 100644 --- a/concepts/properties/about.md +++ b/concepts/properties/about.md @@ -1 +1,80 @@ -TODO: add information on properties concept +The two main types of property are + +1. auto-implemented properties where the `get` and `set` accessors have no body. + They may or may not be explicitly initialized. For example: + ```csharp + public int MyProperty {get; set;} = 42; + ``` +2. those where the accessors evaluate expressions and execute statements. The code can + be as simple as returning or assigning a backing field. For example: + ```csharp + private int myField; + public int MyProperty + { + get { return myField; } + set { myField = value; } + } + ``` + +There is considerable overlap of behaviour and power between properties and methods. +When they are not auto-implemented properties can contain any statement or expression +that can appear within the scope of the class. In a common case they are often described +as wrapping a backing field. +Although much of the time it is obvious whether to code behaviour as a property or method in a particular case it is +often a judgement call for the coder and in particular how much code should be +executed within the accessors. Validation in a set accessor and simple calculation or formatting in a +get accessor are commonly found: + +```csharp +private float fraction; +public float Percentage +{ + get { return fraction * 100; } + set + { + if (value < 0 || value > 100) + { + throw new ArgumentException("Percentage must be between 0 and 100"); + } + fraction = value / 100; + } +} +``` + +In a similar way to other class members properties can have access levels. +Most often properties will have a non-private access level in line with +their essential purpose. Sometimes one of the accessors will have +a different access level to the property. In the case of `TareWeight` +under the rather artificial "security" constraint there was an opportunity +to have a public property with a private getter. This means that code external +to the class can set the value of the property but it can only be read (get) by code within +the class. + +```csharp +public int ConfidentialValueUsedInternally {private get; set; } +``` + +Non-public set accessors are also supported but a more common case is where +the set accessor may be ommitted completely. This is maybe because +the value of the property is set in the class's constructor. + +```csharp +class MyClass +{ + public MyClass( int importantValue) + { + ConstructedValue = importantValue; + } + public int ConstructedValue {get;} +} +``` + +This exercise has dealt with basic use of properties. You will find more advanced +topics in other exercises: + +- expression bodied properties, get accessors and set accessors (covered by expression-bodied members) +- properties on interfaces (covered by Interfaces) +- properties/absract properties on abstract classes (covered by Inheritance) +- use of the `readonly` keyword with properties (covered by Immutability) +- static properties (covered by Statics) +- indexers (covered by Indexers) diff --git a/exercises/concept/properties/.docs/after.md b/exercises/concept/properties/.docs/after.md deleted file mode 100644 index 7882cf52a1..0000000000 --- a/exercises/concept/properties/.docs/after.md +++ /dev/null @@ -1,80 +0,0 @@ -The two main types of property are - -1. auto-implemented properties where the `get` and `set` accessors have no body. - They may or may not be explicitly initialized. For example: - ```csharp - public int MyProperty {get; set;} = 42; - ``` -2. those where the accessors evaluate expressions and execute statements. The code can - be as simple as returning or assigning a backing field. For example: - ```csharp - private int myField; - public int MyProperty - { - get { return myField; } - set { myField = value; } - } - ``` - -There is considerable overlap of behaviour and power between properties and methods. -When they are not auto-implemented properties can contain any statement or expression -that can appear within the scope of the class. In a common case they are often described -as wrapping a backing field. -Although much of the time it is obvious whether to code behaviour as a property or method in a particular case it is -often a judgement call for the coder and in particular how much code should be -executed within the accessors. Validation in a set accessor and simple calculation or formatting in a -get accessor are commonly found: - -```csharp -private float fraction; -public float Percentage -{ - get { return fraction * 100; } - set - { - if (value < 0 || value > 100) - { - throw new ArgumentException("Percentage must be between 0 and 100"); - } - fraction = value / 100; - } -} -``` - -In a similar way to other class members properties can have access levels. -Most often properties will have a non-private access level in line with -their essential purpose. Sometimes one of the accessors will have -a different access level to the property. In the case of `TareWeight` -under the rather artificial "security" constraint there was an opportunity -to have a public property with a private getter. This means that code external -to the class can set the value of the property but it can only be read (get) by code within -the class. - -```csharp -public int ConfidentialValueUsedInternally {private get; set; } -``` - -Non-public set accessors are also supported but a more common case is where -the set accessor may be ommitted completely. This is maybe because -the value of the property is set in the class's constructor. - -```csharp -class MyClass -{ - public MyClass( int importantValue) - { - ConstructedValue = importantValue; - } - public int ConstructedValue {get;} -} -``` - -This exercise has dealt with basic use of properties. You will find more advanced -topics in other exercises: - -- expression bodied properties, get accessors and set accessors (covered by expression-bodied members) -- properties on interfaces (covered by Interfaces) -- properties/absract properties on abstract classes (covered by Inheritance) -- use of the `readonly` keyword with properties (covered by Immutability) -- static properties (covered by Statics) -- indexers (covered by Indexers) From 3c018265158318fb14221253b0b328771f4321d5 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:42:08 +0200 Subject: [PATCH 221/327] parameters - replace about.md file with concept files * Pre-populate parameters concept's about.md file from after.md file * Pre-populate parameters concept's links.json file from after.md file * parameters - Remove after.md document --- concepts/parameters/about.md | 91 ++++++++++++++++++++- concepts/parameters/links.json | 55 ++++++++++++- exercises/concept/parameters/.docs/after.md | 90 -------------------- 3 files changed, 144 insertions(+), 92 deletions(-) delete mode 100644 exercises/concept/parameters/.docs/after.md diff --git a/concepts/parameters/about.md b/concepts/parameters/about.md index 3a469a0a37..019f5aafc3 100644 --- a/concepts/parameters/about.md +++ b/concepts/parameters/about.md @@ -1 +1,90 @@ -TODO: add information on parameters concept +The coding exercise illustrates a number of properties of parameters: + +- Parameters [passed][passing-parameters] without a modifier (such as `out` or `ref`) are passed by value. That is to say that the parameter can be used and assigned to in the called method but any changes will have no effect on the caller. +- When a reference to an array or an instance of a class is a parameter the elements/fields of that instance can be changed by the called method and the changes seen by the caller. This applies irrespective of whether the `ref` modifier is present. +- A parameter with the [`out`][out-parameter] modifier conveys a value back from the called method to the caller. The parameter can be passed to the called method without being initialized and in any case it is treated within the called method as if, on entry, it had not been initialized. An understanding of the behavior and rules regarding parameter modifiers can be gained most easily through examples (see below) and compiler messages. + +```csharp +void Foo(out int val) +{ + val = 42; +} +void Bar(int val) +{ + val = 42; +} + +int importantValue = 1729; +Foo(out importantValue); +var result = importantValue == 42; +// => true + +importantValue = 1729; +Bar(importantValue); +result = importantValue == 1729; +// => true +``` + +- `out` parameters must be assigned to within a called method. + +- A parameter with the [`ref`][ref-parameter] modifier passes a value into a called method. When the method returns the caller will find any updates made by the called method in that parameter. + +```csharp +void Foo(ref int val) +{ + val *= 7; +} + +int importantValue = 6; +Foo(ref importantValue); +return importantValue; +// => 42 +``` + +-`ref` parameters must be variables as the called method will be operating directly on the parameter as seen by the caller. + +- The `out` and `ref` modifiers are required both in the called method signature and at the call site. +- `out` parameters can be declared inline at the call site viz: `Foo(out int importantValue);` +- If you make a call to a method which has `out` parameters but you are not interested in the value assigned to one or more of them then you can use the [discard][discard] dummy variable `_`, as in: `Foo(out int _);` + +All the rules regarding `ref` and `out` parameters are enforced by the compiler. + +[`in`][in-parameter] parameters also exist but they are principally a performance optimisation and are discussed in the `structs` exercise where they are most relevant. + +The documentation linked to above is summarised below: + +- [passing-parameters][passing-parameters]: explains how values can be passed as arguments. Note that the subject of structs+parameters is discussed in the `structs` exercise. +- [ref-parameter][ref-parameter]: describes how `ref` parameters work. +- [out-parameter][out-parameter]: describes how `out` parameters work. + +When studying the documentation note that it uses the following terms: + +- parameter / formal parameter: refers to the parameter as seen by the called method. +- argument: refers to the parameter as seen by the caller. + +[Arguably][so-tuples-vs-out] much of the value of `out` parameters has been eliminated by the introduction of `tuples` in C# 7. The `tuples` exercise shows `tuples` being used to return multiple values. + +Whilst `ref` is easy to use and has no performance penalties it is worth seeing how the problems it addresses are dealt with in a particular code base before using it widely. There are alternatives such as passing in by-value and using the value from the called method's return statement. Again, `tuples` can play a role. + +You will see from the [documentation][ref-parameter] that `out` and `ref` cannot be used in certain situations but you can ignore them for now. The compiler will let you know whwn such situations arise. + +Note that `optional parameters` and `named arguments` are discussed in the `method-overloading` exercise. + +The related topics of [`ref local`][ref-local] and [`ref return`][ref-return] are discussed elsewhere. + +### Stack Allocations + +The rules regarding parameters and their modifiers are sufficiently straightforward that you can take them at face value and understand them at their level of abstraction. However, if you are interested in the underlying mechanisms and why these keywords may make a performance difference, at least in the case of `struct`s, then you could start with this [_Wikipedia article_][calling-conventions], noting that C# uses `stdcall` on x86/64. + +The essence of the story is that in the case of unmodified parameters the **value** of a variable is copied onto the program's stack to make it available to a called routine whereas for `ref`, `out` and `in` parameters a pointer (**reference**) to the memory containing the value is placed on the program's stack and values are assigned to the memory pointed at by the reference. + +[passing-parameters]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters +[ref-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference +[in-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier +[out-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier +[discard]: https://docs.microsoft.com/en-us/dotnet/csharp/discards +[calling-conventions]: https://en.wikipedia.org/wiki/X86_calling_conventions +[so-java-parameters]: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value +[ref-local]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-locals +[ref-return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values +[so-tuples-vs-out]: https://stackoverflow.com/questions/6381918/returning-two-values-tuple-vs-out-vs-struct diff --git a/concepts/parameters/links.json b/concepts/parameters/links.json index fe51488c70..77d7641e3f 100644 --- a/concepts/parameters/links.json +++ b/concepts/parameters/links.json @@ -1 +1,54 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters", + "description": "passing-parameters" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier", + "description": "out-parameter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference", + "description": "ref-parameter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/discards", + "description": "discard" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier", + "description": "in-parameter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters", + "description": "passing-parameters" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference", + "description": "ref-parameter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier", + "description": "out-parameter" + }, + { + "url": "https://stackoverflow.com/questions/6381918/returning-two-values-tuple-vs-out-vs-struct", + "description": "so-tuples-vs-out" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference", + "description": "ref-parameter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-locals", + "description": "ref-local" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values", + "description": "ref-return" + }, + { + "url": "https://en.wikipedia.org/wiki/X86_calling_conventions", + "description": "calling-conventions" + } +] diff --git a/exercises/concept/parameters/.docs/after.md b/exercises/concept/parameters/.docs/after.md deleted file mode 100644 index 019f5aafc3..0000000000 --- a/exercises/concept/parameters/.docs/after.md +++ /dev/null @@ -1,90 +0,0 @@ -The coding exercise illustrates a number of properties of parameters: - -- Parameters [passed][passing-parameters] without a modifier (such as `out` or `ref`) are passed by value. That is to say that the parameter can be used and assigned to in the called method but any changes will have no effect on the caller. -- When a reference to an array or an instance of a class is a parameter the elements/fields of that instance can be changed by the called method and the changes seen by the caller. This applies irrespective of whether the `ref` modifier is present. -- A parameter with the [`out`][out-parameter] modifier conveys a value back from the called method to the caller. The parameter can be passed to the called method without being initialized and in any case it is treated within the called method as if, on entry, it had not been initialized. An understanding of the behavior and rules regarding parameter modifiers can be gained most easily through examples (see below) and compiler messages. - -```csharp -void Foo(out int val) -{ - val = 42; -} -void Bar(int val) -{ - val = 42; -} - -int importantValue = 1729; -Foo(out importantValue); -var result = importantValue == 42; -// => true - -importantValue = 1729; -Bar(importantValue); -result = importantValue == 1729; -// => true -``` - -- `out` parameters must be assigned to within a called method. - -- A parameter with the [`ref`][ref-parameter] modifier passes a value into a called method. When the method returns the caller will find any updates made by the called method in that parameter. - -```csharp -void Foo(ref int val) -{ - val *= 7; -} - -int importantValue = 6; -Foo(ref importantValue); -return importantValue; -// => 42 -``` - --`ref` parameters must be variables as the called method will be operating directly on the parameter as seen by the caller. - -- The `out` and `ref` modifiers are required both in the called method signature and at the call site. -- `out` parameters can be declared inline at the call site viz: `Foo(out int importantValue);` -- If you make a call to a method which has `out` parameters but you are not interested in the value assigned to one or more of them then you can use the [discard][discard] dummy variable `_`, as in: `Foo(out int _);` - -All the rules regarding `ref` and `out` parameters are enforced by the compiler. - -[`in`][in-parameter] parameters also exist but they are principally a performance optimisation and are discussed in the `structs` exercise where they are most relevant. - -The documentation linked to above is summarised below: - -- [passing-parameters][passing-parameters]: explains how values can be passed as arguments. Note that the subject of structs+parameters is discussed in the `structs` exercise. -- [ref-parameter][ref-parameter]: describes how `ref` parameters work. -- [out-parameter][out-parameter]: describes how `out` parameters work. - -When studying the documentation note that it uses the following terms: - -- parameter / formal parameter: refers to the parameter as seen by the called method. -- argument: refers to the parameter as seen by the caller. - -[Arguably][so-tuples-vs-out] much of the value of `out` parameters has been eliminated by the introduction of `tuples` in C# 7. The `tuples` exercise shows `tuples` being used to return multiple values. - -Whilst `ref` is easy to use and has no performance penalties it is worth seeing how the problems it addresses are dealt with in a particular code base before using it widely. There are alternatives such as passing in by-value and using the value from the called method's return statement. Again, `tuples` can play a role. - -You will see from the [documentation][ref-parameter] that `out` and `ref` cannot be used in certain situations but you can ignore them for now. The compiler will let you know whwn such situations arise. - -Note that `optional parameters` and `named arguments` are discussed in the `method-overloading` exercise. - -The related topics of [`ref local`][ref-local] and [`ref return`][ref-return] are discussed elsewhere. - -### Stack Allocations - -The rules regarding parameters and their modifiers are sufficiently straightforward that you can take them at face value and understand them at their level of abstraction. However, if you are interested in the underlying mechanisms and why these keywords may make a performance difference, at least in the case of `struct`s, then you could start with this [_Wikipedia article_][calling-conventions], noting that C# uses `stdcall` on x86/64. - -The essence of the story is that in the case of unmodified parameters the **value** of a variable is copied onto the program's stack to make it available to a called routine whereas for `ref`, `out` and `in` parameters a pointer (**reference**) to the memory containing the value is placed on the program's stack and values are assigned to the memory pointed at by the reference. - -[passing-parameters]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-parameters -[ref-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#passing-an-argument-by-reference -[in-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/in-parameter-modifier -[out-parameter]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/out-parameter-modifier -[discard]: https://docs.microsoft.com/en-us/dotnet/csharp/discards -[calling-conventions]: https://en.wikipedia.org/wiki/X86_calling_conventions -[so-java-parameters]: https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value -[ref-local]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#ref-locals -[ref-return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/ref#reference-return-values -[so-tuples-vs-out]: https://stackoverflow.com/questions/6381918/returning-two-values-tuple-vs-out-vs-struct From bca5f5064ed131e544e1246a450e15102872c047 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:44:52 +0200 Subject: [PATCH 222/327] operator-overloading - replace about.md file with concept files * Pre-populate operator-overloading concept's about.md file from after.md file * Pre-populate operator-overloading concept's links.json file from after.md file * operator-overloading - Remove after.md document --- concepts/operator-overloading/about.md | 82 ++++++++++++++++++- concepts/operator-overloading/links.json | 27 +++++- .../operator-overloading/.docs/after.md | 81 ------------------ 3 files changed, 107 insertions(+), 83 deletions(-) delete mode 100644 exercises/concept/operator-overloading/.docs/after.md diff --git a/concepts/operator-overloading/about.md b/concepts/operator-overloading/about.md index 73c270c9a0..d0fb4ff52b 100644 --- a/concepts/operator-overloading/about.md +++ b/concepts/operator-overloading/about.md @@ -1 +1,81 @@ -TODO: add information on operator-overloading concept +The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_. + +This [article][operator-overloading] is a thorough discussion of the syntax as well as which operators can be overloaded and those that can't. + +Most operators have the form: + +```csharp +static operaator (); +``` + +[Cast operators][ud-conversion-operators] have the form: + +```csharp +static (explicit|implicit) operator ( ); +``` + +Operators behave in the same way as static methods. + +- An operator symbol takes the place of a method identifier, and they have parameters and a return type. The type rules for parameters and return type follow your intuition and you can rely on the compiler to provide detailed guidance. +- For binary operations the first parameter takes the left-hand argument to the operation. +- Operators have a signature comprising two parameters (in the case of binary operations) and a return type or a single parameter and return type in the case of unary operators. +- For binary operators, one of the parameter types must be that of the declaring class. +- In the case of type conversions either the parameter or the return type must be the type of the declaring class. +- For incrementing and decrementing operators the parameter and return type must be that of the declaring class. + +Syntax examples: + +```csharp +struct Point +{ + decimal x; + decimal y; + + public static bool operator ==(Point pt, Point ptOther) + { + return pt.x == ptOther.x && pt.y == ptOther.y; + } + + public static bool operator !=(Point pt, Point ptOther) + { + return !(pt == ptOther); + } + + public static Point operator *(Point pt, decimal scale) + { + var ptNew = new Point(); + ptNew.x = pt.x * scale; + ptNew.y = pt.y * scale; + return ptNew; + } + + public static implicit operator Point((decimal x, decimal y) xy) + { + var pt = new Point(); + pt.x = xy.x; + pt.y = xy.y; + return pt; + } + + public static explicit operator (decimal x, decimal y)(Point pt) + { + return (pt.x, pt.y); + } +} +``` + +It is often productive to implement an [`Equals()`][equals] method and call it from the `==` operator. Similarly, for comparisons you can implement the [`IComparable`][icomparable] interface. In both cases you get to kill two birds with just over one stone. + +You should note that you cannot create operators from symbols that are not part of the standard set of operators. You can use only existing symbols for those operations where the documentation specifies that they can be overloaded. The operators that can be overloaded are listed [here][overloadable-operators]. + +Note that the order of parameters is important where they differ in type. In the above example code `pt * 10m` is a legal expression whereas `10m * pt` will not compile. + +#### Reference + +This documentation of [operator overloading][operator-overloading] details the syntax. + +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[ud-conversion-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators +[overloadable-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading#overloadable-operators +[equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ +[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 diff --git a/concepts/operator-overloading/links.json b/concepts/operator-overloading/links.json index fe51488c70..cbd1f56388 100644 --- a/concepts/operator-overloading/links.json +++ b/concepts/operator-overloading/links.json @@ -1 +1,26 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading", + "description": "operator-overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators", + "description": "ud-conversion-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_", + "description": "equals" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1", + "description": "icomparable" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading#overloadable-operators", + "description": "overloadable-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading", + "description": "operator-overloading" + } +] diff --git a/exercises/concept/operator-overloading/.docs/after.md b/exercises/concept/operator-overloading/.docs/after.md deleted file mode 100644 index d0fb4ff52b..0000000000 --- a/exercises/concept/operator-overloading/.docs/after.md +++ /dev/null @@ -1,81 +0,0 @@ -The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_. - -This [article][operator-overloading] is a thorough discussion of the syntax as well as which operators can be overloaded and those that can't. - -Most operators have the form: - -```csharp -static operaator (); -``` - -[Cast operators][ud-conversion-operators] have the form: - -```csharp -static (explicit|implicit) operator ( ); -``` - -Operators behave in the same way as static methods. - -- An operator symbol takes the place of a method identifier, and they have parameters and a return type. The type rules for parameters and return type follow your intuition and you can rely on the compiler to provide detailed guidance. -- For binary operations the first parameter takes the left-hand argument to the operation. -- Operators have a signature comprising two parameters (in the case of binary operations) and a return type or a single parameter and return type in the case of unary operators. -- For binary operators, one of the parameter types must be that of the declaring class. -- In the case of type conversions either the parameter or the return type must be the type of the declaring class. -- For incrementing and decrementing operators the parameter and return type must be that of the declaring class. - -Syntax examples: - -```csharp -struct Point -{ - decimal x; - decimal y; - - public static bool operator ==(Point pt, Point ptOther) - { - return pt.x == ptOther.x && pt.y == ptOther.y; - } - - public static bool operator !=(Point pt, Point ptOther) - { - return !(pt == ptOther); - } - - public static Point operator *(Point pt, decimal scale) - { - var ptNew = new Point(); - ptNew.x = pt.x * scale; - ptNew.y = pt.y * scale; - return ptNew; - } - - public static implicit operator Point((decimal x, decimal y) xy) - { - var pt = new Point(); - pt.x = xy.x; - pt.y = xy.y; - return pt; - } - - public static explicit operator (decimal x, decimal y)(Point pt) - { - return (pt.x, pt.y); - } -} -``` - -It is often productive to implement an [`Equals()`][equals] method and call it from the `==` operator. Similarly, for comparisons you can implement the [`IComparable`][icomparable] interface. In both cases you get to kill two birds with just over one stone. - -You should note that you cannot create operators from symbols that are not part of the standard set of operators. You can use only existing symbols for those operations where the documentation specifies that they can be overloaded. The operators that can be overloaded are listed [here][overloadable-operators]. - -Note that the order of parameters is important where they differ in type. In the above example code `pt * 10m` is a legal expression whereas `10m * pt` will not compile. - -#### Reference - -This documentation of [operator overloading][operator-overloading] details the syntax. - -[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading -[ud-conversion-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators -[overloadable-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading#overloadable-operators -[equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ -[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 From 9a4985137beef981155cae1080ca95c7eae17f28 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:45:49 +0200 Subject: [PATCH 223/327] object-initializers - replace about.md file with concept files * Pre-populate object-initializers concept's about.md file from after.md file * Pre-populate object-initializers concept's links.json file from after.md file * object-initializers - Remove after.md document --- concepts/object-initializers/about.md | 42 ++++++++++++++++++- concepts/object-initializers/links.json | 11 ++++- .../object-initializers/.docs/after.md | 41 ------------------ 3 files changed, 51 insertions(+), 43 deletions(-) delete mode 100644 exercises/concept/object-initializers/.docs/after.md diff --git a/concepts/object-initializers/about.md b/concepts/object-initializers/about.md index e1eaca8302..248bf7f518 100644 --- a/concepts/object-initializers/about.md +++ b/concepts/object-initializers/about.md @@ -1 +1,41 @@ -TODO: add information on object-initializers concept +Object initializers are an alternative to constructors. The syntax is a comma separated list of field name=value pairs, illustrated below: + +```csharp +public class Person +{ + public string Name; + public string Address; +} + +var person = new Person{Name="The President", Address = "Élysée Palace"}; +``` + +Collections can also be initialized in this way. Typically, this is accomplished with comma separated lists as shown here: + +```csharp +IList people = new List{ new Person(), new Person{Name="Joe Shmo"}}; +``` + +This approach (and syntax) can be used with any class that implements `IEnumerable` and has an `Add()` method. + +Fields can be listed in any order or ommitted completely. + +Dictionaries use the following syntax: + +```csharp +IDictionary numbers = new Dictionary{ [0] = "zero", [1] = "one"...}; + +// or + +IDictionary numbers = new Dictionary{ {0, "zero" }, {1, "one"}...}; +``` + +The initialized fields must be accessible to the caller. Typically, this means they must be `public` or `internal`. + +There is a strong trend promoting immutability amongst the language designers and leading practitioners, so the mutability of objects initialized in this way is seen as a disadvantage. There are proposals to introduce an `init` clause in the upcoming version of the language, C# 9, which may address this. + +- [object initializer][object-initializers] documentation describes how to use initialzers. +- [collection initializer][collection-initializers] documentation gives a preview of how initializers can be used with collections like dictionaries and lists. + +[object-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers +[collection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers diff --git a/concepts/object-initializers/links.json b/concepts/object-initializers/links.json index fe51488c70..2a492b9a23 100644 --- a/concepts/object-initializers/links.json +++ b/concepts/object-initializers/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers", + "description": "object-initializers" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers", + "description": "collection-initializers" + } +] diff --git a/exercises/concept/object-initializers/.docs/after.md b/exercises/concept/object-initializers/.docs/after.md deleted file mode 100644 index 248bf7f518..0000000000 --- a/exercises/concept/object-initializers/.docs/after.md +++ /dev/null @@ -1,41 +0,0 @@ -Object initializers are an alternative to constructors. The syntax is a comma separated list of field name=value pairs, illustrated below: - -```csharp -public class Person -{ - public string Name; - public string Address; -} - -var person = new Person{Name="The President", Address = "Élysée Palace"}; -``` - -Collections can also be initialized in this way. Typically, this is accomplished with comma separated lists as shown here: - -```csharp -IList people = new List{ new Person(), new Person{Name="Joe Shmo"}}; -``` - -This approach (and syntax) can be used with any class that implements `IEnumerable` and has an `Add()` method. - -Fields can be listed in any order or ommitted completely. - -Dictionaries use the following syntax: - -```csharp -IDictionary numbers = new Dictionary{ [0] = "zero", [1] = "one"...}; - -// or - -IDictionary numbers = new Dictionary{ {0, "zero" }, {1, "one"}...}; -``` - -The initialized fields must be accessible to the caller. Typically, this means they must be `public` or `internal`. - -There is a strong trend promoting immutability amongst the language designers and leading practitioners, so the mutability of objects initialized in this way is seen as a disadvantage. There are proposals to introduce an `init` clause in the upcoming version of the language, C# 9, which may address this. - -- [object initializer][object-initializers] documentation describes how to use initialzers. -- [collection initializer][collection-initializers] documentation gives a preview of how initializers can be used with collections like dictionaries and lists. - -[object-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#object-initializers -[collection-initializers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/object-and-collection-initializers#collection-initializers From 203d2816607e0ea35dfe259ca194c0519290dcf3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 09:50:53 +0200 Subject: [PATCH 224/327] nullability - replace about.md file with concept files * Pre-populate nullability concept's about.md file from after.md file * Pre-populate nullability concept's links.json file from after.md file * nullability - Remove after.md document --- concepts/nullability/about.md | 103 ++++++++++++++++++- concepts/nullability/links.json | 39 ++++++- exercises/concept/nullability/.docs/after.md | 102 ------------------ 3 files changed, 140 insertions(+), 104 deletions(-) delete mode 100644 exercises/concept/nullability/.docs/after.md diff --git a/concepts/nullability/about.md b/concepts/nullability/about.md index b19fe3c214..a7b26495cb 100644 --- a/concepts/nullability/about.md +++ b/concepts/nullability/about.md @@ -1 +1,102 @@ -TODO: add information on nullability concept +In C#, the [`null` literal][null-keyword] is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values. + +Prior to C# 8.0, reference types were always nullable and value types were not. A [value type can be made nullable][nullable-value-types] though by appending it with a question mark (`?`). + +```csharp +string nullableReferenceType = "hello"; +nullableReferenceType = null; // Valid as type is nullable + +int nonNullableValueType = 5; +nonNullableValueType = null; // Compile error as type is not nullable + +int? nullableValueType = 5; // Define nullable value type +nullableValueType = null; // Valid as type is nullable +``` + +Accessing a member of a variable which value is `null` will compile fine, but result in a `NullReferenceException` being thrown at runtime: + +```csharp +string sentence = "What a nice day!"; + +// Throws NullReferenceException at runtime +sentence.Length; +``` + +To counter this common type of mistake, C# 8 allows one to [opt-into a feature][nullable-csharp-8] that makes [reference types non-nullable by default][nullable-reference-types]: + +```csharp +string nonNullableReferenceType = "book"; +nonNullableReferenceType = null; // Compile warning (no error!) + +string? nullableReferenceType = "movie"; +nullableReferenceType = null; // Valid as type is nullable +``` + +To [safely work with nullable values][nullable-types-tutorial], one should check if they are `null` before working with them: + +```csharp +string NormalizedName(string? name) +{ + if (name == null) + { + return "UNKNOWN"; + } + else + { + // Value is not null at this point, so no compile warning + // and no runtime NullReferenceException being thrown + return name.ToUpper(); + } +} + +NormalizedName(null); // => "UNKNOWN" +NormalizedName("Elisabeth"); // => "ELISABETH" +``` + +The [`??` operator][null-coalescing-operator] allows one to return a default value when the value is `null`: + +```csharp +string? name1 = "John"; +name1 ?? "Paul"; // => "John" + +string? name2 = null; +name2 ?? "George"; // => "George" +``` + +The [`?.` operator][null-conditional-operator] allows one to call members safely on a possibly `null` value: + +```csharp +string? fruit = "apple"; +fruit?.Length; // => 5 + +string? vegetable = null; +vegetable?.Length; // => null +``` + +If the compiler thinks a value could be `null` but you are certain it won't be, the [`!.` operator][null-forgiving-operator] can be used to suppress the warning. Only use this operator as a last resort though. + +```csharp +void PrintName(string? name) +{ + // Assume that the IsValid() method only return true + // when its argument is not null + if (IsValid(name)) + { + // No compile warning + Console.WriteLine(name!.Length); + } +} +``` + +If you'd like to learn more about working with nullable reference, check out [this tutorial][nullable-reference-types-tutorial]. + +[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null +[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ +[nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[nullable-value-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types +[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references +[null-forgiving-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving +[null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator +[null-conditional-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and- +[nullable-reference-types-tutorial]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types diff --git a/concepts/nullability/links.json b/concepts/nullability/links.json index fe51488c70..4d182dbd22 100644 --- a/concepts/nullability/links.json +++ b/concepts/nullability/links.json @@ -1 +1,38 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null", + "description": "null-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types", + "description": "nullable-value-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references", + "description": "nullable-csharp-8" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references", + "description": "nullable-reference-types" + }, + { + "url": "https://csharp.net-tutorials.com/data-types/nullable-types/", + "description": "nullable-types-tutorial" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator", + "description": "null-coalescing-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-", + "description": "null-conditional-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving", + "description": "null-forgiving-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types", + "description": "nullable-reference-types-tutorial" + } +] diff --git a/exercises/concept/nullability/.docs/after.md b/exercises/concept/nullability/.docs/after.md deleted file mode 100644 index a7b26495cb..0000000000 --- a/exercises/concept/nullability/.docs/after.md +++ /dev/null @@ -1,102 +0,0 @@ -In C#, the [`null` literal][null-keyword] is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values. - -Prior to C# 8.0, reference types were always nullable and value types were not. A [value type can be made nullable][nullable-value-types] though by appending it with a question mark (`?`). - -```csharp -string nullableReferenceType = "hello"; -nullableReferenceType = null; // Valid as type is nullable - -int nonNullableValueType = 5; -nonNullableValueType = null; // Compile error as type is not nullable - -int? nullableValueType = 5; // Define nullable value type -nullableValueType = null; // Valid as type is nullable -``` - -Accessing a member of a variable which value is `null` will compile fine, but result in a `NullReferenceException` being thrown at runtime: - -```csharp -string sentence = "What a nice day!"; - -// Throws NullReferenceException at runtime -sentence.Length; -``` - -To counter this common type of mistake, C# 8 allows one to [opt-into a feature][nullable-csharp-8] that makes [reference types non-nullable by default][nullable-reference-types]: - -```csharp -string nonNullableReferenceType = "book"; -nonNullableReferenceType = null; // Compile warning (no error!) - -string? nullableReferenceType = "movie"; -nullableReferenceType = null; // Valid as type is nullable -``` - -To [safely work with nullable values][nullable-types-tutorial], one should check if they are `null` before working with them: - -```csharp -string NormalizedName(string? name) -{ - if (name == null) - { - return "UNKNOWN"; - } - else - { - // Value is not null at this point, so no compile warning - // and no runtime NullReferenceException being thrown - return name.ToUpper(); - } -} - -NormalizedName(null); // => "UNKNOWN" -NormalizedName("Elisabeth"); // => "ELISABETH" -``` - -The [`??` operator][null-coalescing-operator] allows one to return a default value when the value is `null`: - -```csharp -string? name1 = "John"; -name1 ?? "Paul"; // => "John" - -string? name2 = null; -name2 ?? "George"; // => "George" -``` - -The [`?.` operator][null-conditional-operator] allows one to call members safely on a possibly `null` value: - -```csharp -string? fruit = "apple"; -fruit?.Length; // => 5 - -string? vegetable = null; -vegetable?.Length; // => null -``` - -If the compiler thinks a value could be `null` but you are certain it won't be, the [`!.` operator][null-forgiving-operator] can be used to suppress the warning. Only use this operator as a last resort though. - -```csharp -void PrintName(string? name) -{ - // Assume that the IsValid() method only return true - // when its argument is not null - if (IsValid(name)) - { - // No compile warning - Console.WriteLine(name!.Length); - } -} -``` - -If you'd like to learn more about working with nullable reference, check out [this tutorial][nullable-reference-types-tutorial]. - -[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references -[null-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/null -[nullable-types-tutorial]: https://csharp.net-tutorials.com/data-types/nullable-types/ -[nullable-reference-types]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references -[nullable-value-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types -[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references -[null-forgiving-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-forgiving -[null-coalescing-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-coalescing-operator -[null-conditional-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and- -[nullable-reference-types-tutorial]: https://docs.microsoft.com/en-us/archive/msdn-magazine/2018/february/essential-net-csharp-8-0-and-nullable-reference-types From 5c45eeb3344cead395a33c5ffbadba32c4ceef06 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:13:45 +0200 Subject: [PATCH 225/327] string-formatting - replace about.md file with concept files * Pre-populate string-formatting concept's about.md file from after.md file * Pre-populate string-formatting concept's links.json file from after.md file * Pre-populate verbatim-strings concept's about.md file from after.md file * Pre-populate verbatim-strings concept's links.json file from after.md file * string-formatting - Remove after.md document * Update about.md * Update links.json * Update about.md * Update links.json * Update links.json * Update about.md Co-authored-by: Mike May --- concepts/string-formatting/about.md | 110 ++++++++++++++- concepts/string-formatting/links.json | 99 ++++++++++++- concepts/verbatim-strings/about.md | 11 +- concepts/verbatim-strings/links.json | 7 +- .../concept/string-formatting/.docs/after.md | 131 ------------------ 5 files changed, 223 insertions(+), 135 deletions(-) delete mode 100644 exercises/concept/string-formatting/.docs/after.md diff --git a/concepts/string-formatting/about.md b/concepts/string-formatting/about.md index ffa8019a90..575859943d 100644 --- a/concepts/string-formatting/about.md +++ b/concepts/string-formatting/about.md @@ -1 +1,109 @@ -TODO: add information on string-formatting concept +Mechanisms for formatting strings are many and various in C#/.NET: everything from simple concatenation of objects through calls to the overridden `object.ToString()` method to use of [`ICustomFormatter`][custom-formatter] (not covered in this exercise). + +The two most common mechanisms for formatting strings are [string interpolation][string-interpolation] and [String.Format()][string-format]. The [`StringBuilder`][string-builder] (cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved. + +#### Using `ToString()` + +`System.Object()` from which all classes and structs inherit has a `ToString()` method. For example `new DateTime(2019, 5, 23).ToString()` will render "05/23/2019 00:00:00" (on a thread with US culture - [see below](#culture)). There are situations such as string concatenation where this default `ToString()` method may be invoked implicitly, `"" + new DateTime(2019, 5, 23)` gives the same result. + +In addition to the default `ToString()` method, types where formatting is an issue will have overloads which take a [_format string_](#bcl-formatters-and-format-strings) or even a [format provider][format-provider]. Notably in the BCL (Base Class Library) these are numbers, dates, enums and GUIDs. + +#### Composite Formatting + +`String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as a _format items_) and a variable number of arguments. The return value resolves each _format item_ using the corresponding argument and combines the resolved values with the fixed text. + +```csharp +string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25)) +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +`Format()` may be a better choice than interpolation where the format is being used in multiple expressions as a kind of template or where incorporating the format, and the expressions to be formatted is too cumbersome such as when [verbatim strings][verbatim-strings] are involved. + +This mechanism is technically known as [_composite formatting_][composite-formatting]. + +A fuller list of string producing methods that take advantage _composite formatting_ is given in this [article][composite-formatting]. + +#### String Interpolation + +Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{[,][:]}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism. + +The expression can comprise anything in scope. _Alignment_ is the length of the "field" in which the text sits. If the _alignment_ is positive then the text is padded with spaces on the left and if it is negative then the padding is to the right of the text. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password." +// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings +``` + +#### Format Items + +The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_. + +A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional _format string_ (introduced with a colon, ":"). + +`{[,][:]}` + +The _alignment_ specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is negative or to the right if it is positive. + +The _format string_ specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a `DateTime` object should be output. + +The following code illustrates display of the date portion of a `DateTime` object and a floating-point number in exponential form. + +```csharp +var loadsOf = 55.5; +var thatDay = new DateTime(2010, 2, 25); +$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password." +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings + +string.Format( + "I had {0:E} bitcoins on {1:d}, the day I forgot my password.", + loadsOf, thatDay) +// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings + +``` + +There is both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format characters. "custom" in this context has nothing to do with the [`ICustomFormatter`][custom-formatter] interface which is used when developing your own custom formatters. + +#### BCL Formatters and Format Strings + +The Base Class Library (BCL) provides 2 formatters: `DateTimeFormatInfo` and `NumberFormatInfo` and 6 groups of format strings. + +The various lists of _format strings_ are below: + +- [Standard numeric format strings][standard-numeric-format-strings] +- [Custom numeric format strings][custom-numeric-format-strings] +- [Standard date and time format strings][standard-date-and-time-format-strings] +- [Custom date and time format strings][custom-date-and-time-format-strings] +- [Enumeration format strings][enum-format-strings] +- [GUID format strings][guid-format-strings] + +`Enum` and `GUID` _format strings_ can be classed as _standard_. Although `enum` and `GUID` have `ToString()` overloads that take an `IFormatProvider` it is not clear that it does anything. + +An attempt is made in the library to instill some consistency into _format strings_ (beyond the fact that they are represented as strings). This push for consistency is found in the standard strings. In reality as a developer you rarely care about the difference between standard and custom strings. Although it is a good idea, if you are implementing formatters for your own classes to echo the existing standard strings if your classes appear to call for it, you can pretty well ignore the difference. + +#### Culture + +Each thread of execution has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted by default with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_. + +`CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture. + +#### Reference Material + +[string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation +[string-interpolation-in-depth]: https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C# +[string-interpolation-advanced]: https://www.meziantou.net/interpolated-strings-advanced-usages.htm +[formatting-types]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types +[standard-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings +[custom-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings +[standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings +[custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings +[string-builder]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/stringbuilder +[format-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.iformatprovider?view=netcore-3.1 +[custom-formatter]: https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1 +[string-format]: https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netcore-3.1#System_String_Format_System_String_System_Object_System_Object_System_Object_ +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 +[composite-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting +[custom-string-interpolation]: https://thomaslevesque.com/2015/02/24/customizing-string-interpolation-in-c-6/ +[enum-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/enumeration-format-strings +[guid-format-strings]: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netcore-3.1 diff --git a/concepts/string-formatting/links.json b/concepts/string-formatting/links.json index fe51488c70..f894683706 100644 --- a/concepts/string-formatting/links.json +++ b/concepts/string-formatting/links.json @@ -1 +1,98 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1", + "description": "custom-formatter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation", + "description": "string-interpolation" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netcore-3.1#System_String_Format_System_String_System_Object_System_Object_System_Object_", + "description": "string-format" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/stringbuilder", + "description": "string-builder" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.iformatprovider?view=netcore-3.1", + "description": "format-provider" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals", + "description": "verbatim-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting", + "description": "composite-formatting" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting", + "description": "composite-formatting" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1", + "description": "custom-formatter" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings", + "description": "standard-numeric-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings", + "description": "custom-numeric-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings", + "description": "standard-date-and-time-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings", + "description": "custom-date-and-time-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/enumeration-format-strings", + "description": "enum-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netcore-3.1", + "description": "guid-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation", + "description": "string-interpolation" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types", + "description": "formatting-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings", + "description": "standard-numeric-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings", + "description": "custom-numeric-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings", + "description": "standard-date-and-time-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings", + "description": "custom-date-and-time-format-strings" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/stringbuilder", + "description": "string-builder" + }, + { + "url": "https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C#", + "description": "string-interpolation-in-depth" + }, + { + "url": "https://www.meziantou.net/interpolated-strings-advanced-usages.htm", + "description": "string-interpolation-advanced" + } +] diff --git a/concepts/verbatim-strings/about.md b/concepts/verbatim-strings/about.md index 313184d669..21fc1b67bd 100644 --- a/concepts/verbatim-strings/about.md +++ b/concepts/verbatim-strings/about.md @@ -1 +1,10 @@ -TODO: add information on verbatim-strings concept +[Verbatim strings][verbatim-strings] allow multi-line strings. They are introduced with an @. They can be used with string interpolation. Just add a "\$" before the opening quote. + +```csharp +string str = @" +See no wretched +quotes everywhere +"; +``` + +[verbatim-strings]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals diff --git a/concepts/verbatim-strings/links.json b/concepts/verbatim-strings/links.json index fe51488c70..addeff8e8f 100644 --- a/concepts/verbatim-strings/links.json +++ b/concepts/verbatim-strings/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals", + "description": "verbatim-strings" + } +] diff --git a/exercises/concept/string-formatting/.docs/after.md b/exercises/concept/string-formatting/.docs/after.md deleted file mode 100644 index 8e1fe58a4b..0000000000 --- a/exercises/concept/string-formatting/.docs/after.md +++ /dev/null @@ -1,131 +0,0 @@ -Mechanisms for formatting strings are many and various in C#/.NET: everything from simple concatenation of objects through calls to the overridden `object.ToString()` method to use of [`ICustomFormatter`][custom-formatter] (not covered in this exercise). - -The two most common mechanisms for formatting strings are [string interpolation][string-interpolation] and [String.Format()][string-format]. The [`StringBuilder`][string-builder] (cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved. - -#### Using `ToString()` - -`System.Object()` from which all classes and structs inherit has a `ToString()` method. For example `new DateTime(2019, 5, 23).ToString()` will render "05/23/2019 00:00:00" (on a thread with US culture - [see below](#culture)). There are situations such as string concatenation where this default `ToString()` method may be invoked implicitly, `"" + new DateTime(2019, 5, 23)` gives the same result. - -In addition to the default `ToString()` method, types where formatting is an issue will have overloads which take a [_format string_](#bcl-formatters-and-format-strings) or even a [format provider][format-provider]. Notably in the BCL (Base Class Library) these are numbers, dates, enums and GUIDs. - -#### Composite Formatting - -`String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as a _format items_) and a variable number of arguments. The return value resolves each _format item_ using the corresponding argument and combines the resolved values with the fixed text. - -```csharp -string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25)) -// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings -``` - -`Format()` may be a better choice than interpolation where the format is being used in multiple expressions as a kind of template or where incorporating the format, and the expressions to be formatted is too cumbersome such as when [verbatim strings][verbatim-strings] are involved. - -This mechanism is technically known as [_composite formatting_][composite-formatting]. - -A fuller list of string producing methods that take advantage _composite formatting_ is given in this [article][composite-formatting]. - -#### String Interpolation - -Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{[,][:]}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism. - -The expression can comprise anything in scope. _Alignment_ is the length of the "field" in which the text sits. If the _alignment_ is positive then the text is padded with spaces on the left and if it is negative then the padding is to the right of the text. - -```csharp -var loadsOf = 55.5; -var thatDay = new DateTime(2010, 2, 25); -$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password." -// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings -``` - -#### Format Items - -The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_. - -A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional _format string_ (introduced with a colon, ":"). - -`{[,][:]}` - -The _alignment_ specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is negative or to the right if it is positive. - -The _format string_ specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a `DateTime` object should be output. - -The following code illustrates display of the date portion of a `DateTime` object and a floating-point number in exponential form. - -```csharp -var loadsOf = 55.5; -var thatDay = new DateTime(2010, 2, 25); -$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password." -// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings - -string.Format( - "I had {0:E} bitcoins on {1:d}, the day I forgot my password.", - loadsOf, thatDay) -// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings - -``` - -There is both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format characters. "custom" in this context has nothing to do with the [`ICustomFormatter`][custom-formatter] interface which is used when developing your own custom formatters. - -#### BCL Formatters and Format Strings - -The Base Class Library (BCL) provides 2 formatters: `DateTimeFormatInfo` and `NumberFormatInfo` and 6 groups of format strings. - -The various lists of _format strings_ are below: - -- [Standard numeric format strings][standard-numeric-format-strings] -- [Custom numeric format strings][custom-numeric-format-strings] -- [Standard date and time format strings][standard-date-and-time-format-strings] -- [Custom date and time format strings][custom-date-and-time-format-strings] -- [Enumeration format strings][enum-format-strings] -- [GUID format strings][guid-format-strings] - -`Enum` and `GUID` _format strings_ can be classed as _standard_. Although `enum` and `GUID` have `ToString()` overloads that take an `IFormatProvider` it is not clear that it does anything. - -An attempt is made in the library to instill some consistency into _format strings_ (beyond the fact that they are represented as strings). This push for consistency is found in the standard strings. In reality as a developer you rarely care about the difference between standard and custom strings. Although it is a good idea, if you are implementing formatters for your own classes to echo the existing standard strings if your classes appear to call for it, you can pretty well ignore the difference. - -#### Culture - -Each thread of execution has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted by default with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_. - -`CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture. - -#### Verbatim Strings - -[Verbatim strings][verbatim-strings] allow multi-line strings. They are introduced with an @. They can be used with string interpolation. Just add a "\$" before the opening quote. - -```csharp -string str = @" -See no wretched -quotes everywhere -"; -``` - -#### Reference Material - -- [String interpolation][string-interpolation]: tutorial on how to use string interpolation. -- [Formatting types][formatting-types]: the available format types to use. -- [Standard numeric format strings][standard-numeric-format-strings]: lists the standard numeric format strings. -- [Custom numeric format strings][custom-numeric-format-strings]: describes how to define custom numeric format strings. -- [Standard date and time format strings][standard-date-and-time-format-strings]: lists the standard date and time format strings. -- [Custom date and time format strings][custom-date-and-time-format-strings]: describes how to define custom date and time format strings. -- [String builder][string-builder]: shows how to use the string builder. -- [String interpolation - in-depth][string-interpolation-in-depth]: in-depth examination of string interpolation, including the generated IL code. -- [String interpolation - advanced][string-interpolation-advanced]: advanced tutorial on string interpolation, includes the `FormattableString` class. - -[string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation -[string-interpolation-in-depth]: https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C# -[string-interpolation-advanced]: https://www.meziantou.net/interpolated-strings-advanced-usages.htm -[formatting-types]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/formatting-types -[standard-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings -[custom-numeric-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-numeric-format-strings -[standard-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings -[custom-date-and-time-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings -[string-builder]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/stringbuilder -[format-provider]: https://docs.microsoft.com/en-us/dotnet/api/system.iformatprovider?view=netcore-3.1 -[custom-formatter]: https://docs.microsoft.com/en-us/dotnet/api/system.icustomformatter?view=netcore-3.1 -[string-format]: https://docs.microsoft.com/en-us/dotnet/api/system.string.format?view=netcore-3.1#System_String_Format_System_String_System_Object_System_Object_System_Object_ -[verbatim-strings]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/strings/#regular-and-verbatim-string-literals -[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 -[composite-formatting]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting -[custom-string-interpolation]: https://thomaslevesque.com/2015/02/24/customizing-string-interpolation-in-c-6/ -[enum-format-strings]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/enumeration-format-strings -[guid-format-strings]: https://docs.microsoft.com/en-us/dotnet/api/system.guid.tostring?view=netcore-3.1 From e2bc7c5a7d65e2e03b623b73271c334e05b32da3 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:16:23 +0200 Subject: [PATCH 226/327] regular-expressions - replace about.md file with concept files * Pre-populate regular-expressions concept's about.md file from after.md file * Pre-populate regular-expressions concept's links.json file from after.md file * regular-expressions - Remove after.md document * Update about.md Co-authored-by: Mike May --- concepts/regular-expressions/about.md | 62 ++++++++++++++++- concepts/regular-expressions/links.json | 31 ++++++++- .../regular-expressions/.docs/after.md | 66 ------------------- 3 files changed, 91 insertions(+), 68 deletions(-) delete mode 100644 exercises/concept/regular-expressions/.docs/after.md diff --git a/concepts/regular-expressions/about.md b/concepts/regular-expressions/about.md index 2e19654931..ef161ce8ca 100644 --- a/concepts/regular-expressions/about.md +++ b/concepts/regular-expressions/about.md @@ -1 +1,61 @@ -TODO: add information on regular-expressions concept +The .NET base class libraries provide the [`Regex`][regex] class for processing of regular expressions. + +See this [article][regex-comparison] for a comparison of C# with other flavours of regular expressions. + +#### Capture Groups + +One aspect to consider is that of capture groups which return parts of the text matching various parts of the regex pattern. The approach to capture groups needs getting used to. See this [documentation][capture]. + +Note that there is a hierarchy where capture groups, `(?pattern)`, are involved: + +- where a set of zero or more matches is returned (one for each match found in the text). +- Each match contains a number of capture groups +- Each group contains a number of captures. + +In addition: + +- `Match` is derived from `Group` +- `Group` is derived from `Capture` + +Caveats: + +- The safest approach is to use named captures. +- Capture groups do generally occur in the `Groups` collection in the same order as they appear in the text. +- `Groups[0]` appears to relate to the entire match. +- `Groups[].Value` is almost certainly what you are interested in. Individual captures (other than `Caputures[0]`) appear to be for intended for diagnostic purposes if they are present. + +#### Regex Options + +Familiarise yourself with [`RegexOptions`][regex-options]. + +As well as the usual `IgnoreCase` options there are ones for `MultiLine` which is useful for processing multiple lines of text in one go and `IgnorePatternWhitespace` which when coupled with verbatim strings, string interpolation and comments can be very expressive as shown in this illustration: + +```csharp +const string PREAMBLE = "preamble"; +const string PWTEXT = "pwtext"; +const string PW = "pw"; +const string SPACE = "space"; +const string POSTAMBLE = "postamble"; + +var pattern = $@" + ^ + (?<{PREAMBLE}>.*) # any text + (?<{PWTEXT}>password) # the literal text - password + (?<{SPACE}>\s+) + (?<{PW}>\w*) # the password itself + (?<{POSTAMBLE}>.*) # any text + $ + "; + +var rewrittenLine = $"{grps[PREAMBLE].Value}{grps[PWTEXT].Value}{grps[SPACE].Value}{mask}{grps[POSTAMBLE].Value}"; +``` + +Another option of interest is `RegexOptions.Compiled` for [compiled][regex-compilation] regexes. + +[regular-expressions]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference +[regex]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1 +[so-groups-and-captures]: https://stackoverflow.com/questions/3320823/whats-the-difference-between-groups-and-captures-in-net-regular-expression +[regex-comparison]: https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines +[capture]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.capturecollection?view=netcore-3.1 +[regex-options]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions?view=netcore-3.1 +[regex-compilation]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices diff --git a/concepts/regular-expressions/links.json b/concepts/regular-expressions/links.json index fe51488c70..661c9ed895 100644 --- a/concepts/regular-expressions/links.json +++ b/concepts/regular-expressions/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1", + "description": "regex" + }, + { + "url": "https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines", + "description": "regex-comparison" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.capturecollection?view=netcore-3.1", + "description": "capture" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions?view=netcore-3.1", + "description": "regex-options" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices", + "description": "regex-compilation" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference", + "description": "regular-expressions" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1", + "description": "regex" + } +] diff --git a/exercises/concept/regular-expressions/.docs/after.md b/exercises/concept/regular-expressions/.docs/after.md deleted file mode 100644 index 74e879a251..0000000000 --- a/exercises/concept/regular-expressions/.docs/after.md +++ /dev/null @@ -1,66 +0,0 @@ -The .NET base class libraries provide the [`Regex`][regex] class for processing of regular expressions. - -See this [article][regex-comparison] for a comparison of C# with other flavours of regular expressions. - -#### Capture Groups - -One aspect to consider is that of capture groups which return parts of the text matching various parts of the regex pattern. The approach to capture groups needs getting used to. See this [documentation][capture]. - -Note that there is a hierarchy where capture groups, `(?pattern)`, are involved: - -- where a set of zero or more matches is returned (one for each match found in the text). -- Each match contains a number of capture groups -- Each group contains a number of captures. - -In addition: - -- `Match` is derived from `Group` -- `Group` is derived from `Capture` - -Caveats: - -- The safest approach is to use named captures. -- Capture groups do generally occur in the `Groups` collection in the same order as they appear in the text. -- `Groups[0]` appears to relate to the entire match. -- `Groups[].Value` is almost certainly what you are interested in. Individual captures (other than `Caputures[0]`) appear to be for intended for diagnostic purposes if they are present. - -#### Regex Options - -Familiarise yourself with [`RegexOptions`][regex-options]. - -As well as the usual `IgnoreCase` options there are ones for `MultiLine` which is useful for processing multiple lines of text in one go and `IgnorePatternWhitespace` which when coupled with verbatim strings, string interpolation and comments can be very expressive as shown in this illustration: - -```csharp -const string PREAMBLE = "preamble"; -const string PWTEXT = "pwtext"; -const string PW = "pw"; -const string SPACE = "space"; -const string POSTAMBLE = "postamble"; - -var pattern = $@" - ^ - (?<{PREAMBLE}>.*) # any text - (?<{PWTEXT}>password) # the literal text - password - (?<{SPACE}>\s+) - (?<{PW}>\w*) # the password itself - (?<{POSTAMBLE}>.*) # any text - $ - "; - -var rewrittenLine = $"{grps[PREAMBLE].Value}{grps[PWTEXT].Value}{grps[SPACE].Value}{mask}{grps[POSTAMBLE].Value}"; -``` - -Another option of interest is `RegexOptions.Compiled` for [compiled][regex-compilation] regexes. - -#### General - -- [regular expressions][regular-expressions] documentation describes regexes and the flavour built into the .NET libraries. -- [Regex][regex] documentation describing the built-in library class. - -[regular-expressions]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/regular-expression-language-quick-reference -[regex]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regex?view=netcore-3.1 -[so-groups-and-captures]: https://stackoverflow.com/questions/3320823/whats-the-difference-between-groups-and-captures-in-net-regular-expression -[regex-comparison]: https://en.wikipedia.org/wiki/Comparison_of_regular-expression_engines -[capture]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.capturecollection?view=netcore-3.1 -[regex-options]: https://docs.microsoft.com/en-us/dotnet/api/system.text.regularexpressions.regexoptions?view=netcore-3.1 -[regex-compilation]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices From 77ae992e3cab6766595d0eeb6b44773563f3c4f5 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:16:53 +0200 Subject: [PATCH 227/327] lists - replace about.md file with concept files * Pre-populate generic-types concept's about.md file from after.md file * Pre-populate generic-types concept's links.json file from after.md file * Pre-populate lists concept's about.md file from after.md file * Pre-populate lists concept's links.json file from after.md file * lists - Remove after.md document * Update about.md * Update links.json * Update about.md * Update links.json Co-authored-by: Mike May --- concepts/generic-types/about.md | 11 +++++++- concepts/generic-types/links.json | 11 +++++++- concepts/lists/about.md | 22 ++++++++++++++- concepts/lists/links.json | 23 +++++++++++++++- exercises/concept/lists/.docs/after.md | 38 -------------------------- 5 files changed, 63 insertions(+), 42 deletions(-) delete mode 100644 exercises/concept/lists/.docs/after.md diff --git a/concepts/generic-types/about.md b/concepts/generic-types/about.md index 8572374ee8..99682785d4 100644 --- a/concepts/generic-types/about.md +++ b/concepts/generic-types/about.md @@ -1 +1,10 @@ -TODO: add information on generic-types concept +Lists are an example of generic classes. You will also see `HashSet` and `Dictionary` in early exercises. + +More [advanced generic techniques][generics] are discussed in (TODO cross-ref-tba) including creating your own generics. + +If you need a list of different types then you can use `List` but you will need to [down cast][casting] elements that you access in from the list. + +You should also be aware of `System.Collections.List` which you may encounter in legacy code. To all intents and purposes this behaves like `List`. + +[generics]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/ +[casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions diff --git a/concepts/generic-types/links.json b/concepts/generic-types/links.json index fe51488c70..716b42ee33 100644 --- a/concepts/generic-types/links.json +++ b/concepts/generic-types/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/", + "description": "generics" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions", + "description": "casting" + } +] diff --git a/concepts/lists/about.md b/concepts/lists/about.md index a324a4ab76..aaf0658df7 100644 --- a/concepts/lists/about.md +++ b/concepts/lists/about.md @@ -1 +1,21 @@ -TODO: add information on lists concept +Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as [`List`][lists-docs] where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. + +```csharp +var listOfStrings = new List(); +var listOfIntegers = new List(); +var listOfRandoms = new List(); +var listOfBigIntegers = new List(); +``` + +A collection definition typically includes a place holder in angle brackets, often `T` by convention. This allows the collection user to specify what type of items to store in the collection. + +Unlike arrays (TODO cross-ref-tba) lists can resize themselves dynamically. + +#### LINQ + +Although the built-in API of `List` is rich (including mappings and filters such as `ConvertAll`, `FindAll` and `Foreach`) and its [looping syntax][for-each] is very clear, and you definitely need to be familiar with this API, Language Integrated Query ([LINQ][linq]) is available for many tasks, is even more powerful and widely used and has the advantage of providing a consistent interface across library collections, third-party collections and your own classes. See (TODO cross-ref-tba). + +[lists-docs]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1 +[lists-tutorial]: https://csharp.net-tutorials.com/collections/lists/ +[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ +[for-each]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in diff --git a/concepts/lists/links.json b/concepts/lists/links.json index fe51488c70..71ea5b5ca3 100644 --- a/concepts/lists/links.json +++ b/concepts/lists/links.json @@ -1 +1,22 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1", + "description": "lists-docs" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in", + "description": "for-each" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/", + "description": "linq" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1", + "description": "lists-docs" + }, + { + "url": "https://csharp.net-tutorials.com/collections/lists/", + "description": "lists-tutorial" + } +] diff --git a/exercises/concept/lists/.docs/after.md b/exercises/concept/lists/.docs/after.md deleted file mode 100644 index 344684188b..0000000000 --- a/exercises/concept/lists/.docs/after.md +++ /dev/null @@ -1,38 +0,0 @@ -Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as [`List`][lists-docs] where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. - -```csharp -var listOfStrings = new List(); -var listOfIntegers = new List(); -var listOfRandoms = new List(); -var listOfBigIntegers = new List(); -``` - -A collection definition typically includes a place holder in angle brackets, often `T` by convention. This allows the collection user to specify what type of items to store in the collection. - -Unlike arrays (TODO cross-ref-tba) lists can resize themselves dynamically. - -#### Generic classes - -Lists are an example of generic classes. You will also see `HashSet` and `Dictionary` in early exercises. - -More [advanced generic techniques][generics] are discussed in (TODO cross-ref-tba) including creating your own generics. - -If you need a list of different types then you can use `List` but you will need to [down cast][casting] elements that you access in from the list. - -You should also be aware of `System.Collections.List` which you may encounter in legacy code. To all intents and purposes this behaves like `List`. - -#### LINQ - -Although the built-in API of `List` is rich (including mappings and filters such as `ConvertAll`, `FindAll` and `Foreach`) and its [looping syntax][for-each] is very clear, and you definitely need to be familiar with this API, Language Integrated Query ([LINQ][linq]) is available for many tasks, is even more powerful and widely used and has the advantage of providing a consistent interface across library collections, third-party collections and your own classes. See (TODO cross-ref-tba). - -#### Reference - -- [List documentation][lists-docs]: reference documentation for `List`. -- [Lists tutorial][lists-tutorial]: basic tutorial on how to work with lists. - -[lists-docs]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1 -[lists-tutorial]: https://csharp.net-tutorials.com/collections/lists/ -[generics]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/ -[casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions -[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ -[for-each]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in From 7599c32b0e61875badbfc013f660a0f246b47a38 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:17:07 +0200 Subject: [PATCH 228/327] method-overloading - replace about.md file with concept files * Pre-populate method-overloading concept's about.md file from after.md file * Pre-populate method-overloading concept's links.json file from after.md file * Pre-populate named-arguments concept's about.md file from after.md file * Pre-populate named-arguments concept's links.json file from after.md file * Pre-populate optional-parameters concept's about.md file from after.md file * Pre-populate optional-parameters concept's links.json file from after.md file * method-overloading - Remove after.md document * Update about.md * Update about.md * Update about.md Co-authored-by: Mike May --- concepts/method-overloading/about.md | 37 ++++++++++++++++++- concepts/method-overloading/links.json | 19 +++++++++- concepts/named-arguments/about.md | 37 ++++++++++++++++++- concepts/named-arguments/links.json | 19 +++++++++- concepts/optional-parameters/about.md | 37 ++++++++++++++++++- concepts/optional-parameters/links.json | 19 +++++++++- .../concept/method-overloading/.docs/after.md | 35 ------------------ 7 files changed, 162 insertions(+), 41 deletions(-) delete mode 100644 exercises/concept/method-overloading/.docs/after.md diff --git a/concepts/method-overloading/about.md b/concepts/method-overloading/about.md index 679c8f4333..7d81482cfb 100644 --- a/concepts/method-overloading/about.md +++ b/concepts/method-overloading/about.md @@ -1 +1,36 @@ -TODO: add information on method-overloading concept +TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case +[_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: + +- The number of parameters +- The type of the parameters + +There is no method overloading based on the return type. + +The compiler will automatically infer which overloaded method to call [based on the number of parameters and their type][overloading]. + +A method parameter can be made optional by assigning it a default value. When a parameter is optional, the caller is not required to supply an argument for that parameter, in which case the default value will be used. [Optional parameters][optional-arguments] _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. If a method has multiple optional parameters, you can specify only some of them using [named arguments][named-arguments]. + +```csharp +class Card +{ + static string NewYear(int year = 2020, string sender = "me") + { + return $"Happy {year} from {sender}!"; + } +} + +Card.NewYear(); // => "Happy 2020 from me!" +Card.Card(1999); // => "Happy 1999 from me!" +Card.Card(sender: "mom"); // => "Happy 2020 from mom!" +``` + +An optional parameter's value must be either: + +- A constant expression (e.g. `"hi"`, `2`, `DayOfWeek.Friday`, `null` etc.) +- A `new` expression of a value type +- A `default` expression of a value type + +[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading +[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments +[named-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments +[overloading]: https://csharpindepth.com/articles/Overloading diff --git a/concepts/method-overloading/links.json b/concepts/method-overloading/links.json index fe51488c70..4729a0e002 100644 --- a/concepts/method-overloading/links.json +++ b/concepts/method-overloading/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading", + "description": "member-overloading" + }, + { + "url": "https://csharpindepth.com/articles/Overloading", + "description": "overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments", + "description": "optional-arguments" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments", + "description": "named-arguments" + } +] diff --git a/concepts/named-arguments/about.md b/concepts/named-arguments/about.md index f005324d6b..7d81482cfb 100644 --- a/concepts/named-arguments/about.md +++ b/concepts/named-arguments/about.md @@ -1 +1,36 @@ -TODO: add information on named-arguments concept +TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case +[_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: + +- The number of parameters +- The type of the parameters + +There is no method overloading based on the return type. + +The compiler will automatically infer which overloaded method to call [based on the number of parameters and their type][overloading]. + +A method parameter can be made optional by assigning it a default value. When a parameter is optional, the caller is not required to supply an argument for that parameter, in which case the default value will be used. [Optional parameters][optional-arguments] _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. If a method has multiple optional parameters, you can specify only some of them using [named arguments][named-arguments]. + +```csharp +class Card +{ + static string NewYear(int year = 2020, string sender = "me") + { + return $"Happy {year} from {sender}!"; + } +} + +Card.NewYear(); // => "Happy 2020 from me!" +Card.Card(1999); // => "Happy 1999 from me!" +Card.Card(sender: "mom"); // => "Happy 2020 from mom!" +``` + +An optional parameter's value must be either: + +- A constant expression (e.g. `"hi"`, `2`, `DayOfWeek.Friday`, `null` etc.) +- A `new` expression of a value type +- A `default` expression of a value type + +[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading +[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments +[named-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments +[overloading]: https://csharpindepth.com/articles/Overloading diff --git a/concepts/named-arguments/links.json b/concepts/named-arguments/links.json index fe51488c70..4729a0e002 100644 --- a/concepts/named-arguments/links.json +++ b/concepts/named-arguments/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading", + "description": "member-overloading" + }, + { + "url": "https://csharpindepth.com/articles/Overloading", + "description": "overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments", + "description": "optional-arguments" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments", + "description": "named-arguments" + } +] diff --git a/concepts/optional-parameters/about.md b/concepts/optional-parameters/about.md index cbed9c5869..7d81482cfb 100644 --- a/concepts/optional-parameters/about.md +++ b/concepts/optional-parameters/about.md @@ -1 +1,36 @@ -TODO: add information on optional-parameters concept +TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case +[_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: + +- The number of parameters +- The type of the parameters + +There is no method overloading based on the return type. + +The compiler will automatically infer which overloaded method to call [based on the number of parameters and their type][overloading]. + +A method parameter can be made optional by assigning it a default value. When a parameter is optional, the caller is not required to supply an argument for that parameter, in which case the default value will be used. [Optional parameters][optional-arguments] _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. If a method has multiple optional parameters, you can specify only some of them using [named arguments][named-arguments]. + +```csharp +class Card +{ + static string NewYear(int year = 2020, string sender = "me") + { + return $"Happy {year} from {sender}!"; + } +} + +Card.NewYear(); // => "Happy 2020 from me!" +Card.Card(1999); // => "Happy 1999 from me!" +Card.Card(sender: "mom"); // => "Happy 2020 from mom!" +``` + +An optional parameter's value must be either: + +- A constant expression (e.g. `"hi"`, `2`, `DayOfWeek.Friday`, `null` etc.) +- A `new` expression of a value type +- A `default` expression of a value type + +[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading +[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments +[named-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments +[overloading]: https://csharpindepth.com/articles/Overloading diff --git a/concepts/optional-parameters/links.json b/concepts/optional-parameters/links.json index fe51488c70..4729a0e002 100644 --- a/concepts/optional-parameters/links.json +++ b/concepts/optional-parameters/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading", + "description": "member-overloading" + }, + { + "url": "https://csharpindepth.com/articles/Overloading", + "description": "overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments", + "description": "optional-arguments" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments", + "description": "named-arguments" + } +] diff --git a/exercises/concept/method-overloading/.docs/after.md b/exercises/concept/method-overloading/.docs/after.md deleted file mode 100644 index 4dc50de6eb..0000000000 --- a/exercises/concept/method-overloading/.docs/after.md +++ /dev/null @@ -1,35 +0,0 @@ -[_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: - -- The number of parameters -- The type of the parameters - -There is no method overloading based on the return type. - -The compiler will automatically infer which overloaded method to call [based on the number of parameters and their type][overloading]. - -A method parameter can be made optional by assigning it a default value. When a parameter is optional, the caller is not required to supply an argument for that parameter, in which case the default value will be used. [Optional parameters][optional-arguments] _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. If a method has multiple optional parameters, you can specify only some of them using [named arguments][named-arguments]. - -```csharp -class Card -{ - static string NewYear(int year = 2020, string sender = "me") - { - return $"Happy {year} from {sender}!"; - } -} - -Card.NewYear(); // => "Happy 2020 from me!" -Card.Card(1999); // => "Happy 1999 from me!" -Card.Card(sender: "mom"); // => "Happy 2020 from mom!" -``` - -An optional parameter's value must be either: - -- A constant expression (e.g. `"hi"`, `2`, `DayOfWeek.Friday`, `null` etc.) -- A `new` expression of a value type -- A `default` expression of a value type - -[member-overloading]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/member-overloading -[optional-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#optional-arguments -[named-arguments]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments -[overloading]: https://csharpindepth.com/articles/Overloading From eea85c62fa095c73b75d618e7a4cb367ce50cc19 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:17:24 +0200 Subject: [PATCH 229/327] namespaces - replace about.md file with concept files * Pre-populate accessibility concept's about.md file from after.md file * Pre-populate accessibility concept's links.json file from after.md file * Pre-populate namespaces concept's about.md file from after.md file * Pre-populate namespaces concept's links.json file from after.md file * namespaces - Remove after.md document * Update about.md * Update links.json * Update about.md Co-authored-by: Mike May --- concepts/namespaces/about.md | 91 +++++++++++++++++++- concepts/namespaces/links.json | 31 ++++++- exercises/concept/namespaces/.docs/after.md | 95 --------------------- 3 files changed, 120 insertions(+), 97 deletions(-) delete mode 100644 exercises/concept/namespaces/.docs/after.md diff --git a/concepts/namespaces/about.md b/concepts/namespaces/about.md index fa1b9f7ff0..0973200a1d 100644 --- a/concepts/namespaces/about.md +++ b/concepts/namespaces/about.md @@ -1 +1,90 @@ -TODO: add information on namespaces concept +It is unlikely that you will come across much production code that does not make use of namespaces. + +An example of the syntax is: + +```csharp +namespace MyNameSpace +{ + public class MyClass {} + + public class OtherClass {} +} +``` + +Namespaces are a way to group related code and to avoid name clashes. + +According to the [official documentation][namespaces] namespaces have two principal roles: + +- First, .NET uses namespaces to organize its many classes +- Second, declaring your own namespaces can help you control the scope of class and method names in larger programming projects. + +Namespaces are used widely by the base class library (BCL) to organize its functionality. + +#### References to namespaced types + +Types enclosed in namespaces are referred to outside the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and any types in the imported namespace can be used without the prefix. Within the same namespace there is no need to qualify type names. + +```csharp +namespace MySpace +{ + public class MyClass {} + + public class Foo + { + public void Bar() + { + var baz = new MyClass(); + } + } +} + +public class Qux +{ + public void Box() + { + var nux = new MySpace.MyClass(); + } +} + +namespace OtherSpace +{ + using MySpace; + + public class Tix + { + public void Jeg() + { + var lor = new MyClass(); + } + } +} +``` + +This [article][using] clearly explains the ways in which the `using` directive can be used: + +- `using`: avoid having to qualify types with namespace +- `using static`: avoid having to qualify members with types (a good example is `Math.Max()`). +- `using MyAlias = YourNamespace;`: substitute a more readable name for the namespace name. + +#### Clash of namespaces + +.NET addresses the issue of two namespaces with the same name in different assemblies where there would be a clash of fully qualified identifier names (perhaps a scenario where multiple versions of an assembly are loaded). This issue is addressed with the [namespace alias qualifier][namespace-alias-qualifier] and the [extern alias][extern-alias]. + +One reason to raise this fairly niche topic is because of its use of the [`::` operator][dot-dot-operator]. You will often see the qualifier `global::` prefixing namespaces, particularly in generated code. The intention here is to avoid a potential clash with some nested namespace or class name. By prefixing a namespace with `global::` you ensure that a top-level namespace is selected. + +#### Note for Java developers + +When comparing with the `import` of Java `packages` some differences and similarities should be noted: + +- There is no equivalent with C# of importing specific types. +- `using static` and `import static` are equivalent. +- In Java, package names have an impact on accessibility as between jars. In C# assemblies are paramount and belonging to the same namespace does not affect access level. +- The relationship between file system paths and fully qualified class names in Java is not reflected in C#'s namespaces although it is good practice where possible to give a file the same name as the principal class it contains. + +[namespaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/ +[accessibility-levels]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels +[namespace-alias-qualifier]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier +[extern-alias]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias +[using]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive +[assemblies]: https://docs.microsoft.com/en-us/dotnet/standard/assembly/ +[dot-dot-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier diff --git a/concepts/namespaces/links.json b/concepts/namespaces/links.json index fe51488c70..7aa1cd6ee9 100644 --- a/concepts/namespaces/links.json +++ b/concepts/namespaces/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/", + "description": "namespaces" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive", + "description": "using" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier", + "description": "namespace-alias-qualifier" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias", + "description": "extern-alias" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier", + "description": "dot-dot-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/", + "description": "namespaces" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels", + "description": "accessibility-levels" + } +] diff --git a/exercises/concept/namespaces/.docs/after.md b/exercises/concept/namespaces/.docs/after.md deleted file mode 100644 index 9be0dea34a..0000000000 --- a/exercises/concept/namespaces/.docs/after.md +++ /dev/null @@ -1,95 +0,0 @@ -It is unlikely that you will come across much production code that does not make use of namespaces. - -An example of the syntax is: - -```csharp -namespace MyNameSpace -{ - public class MyClass {} - - public class OtherClass {} -} -``` - -Namespaces are a way to group related code and to avoid name clashes. - -According to the [official documentation][namespaces] namespaces have two principal roles: - -- First, .NET uses namespaces to organize its many classes -- Second, declaring your own namespaces can help you control the scope of class and method names in larger programming projects. - -Namespaces are used widely by the base class library (BCL) to organize its functionality. - -#### References to namespaced types - -Types enclosed in namespaces are referred to outside the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and any types in the imported namespace can be used without the prefix. Within the same namespace there is no need to qualify type names. - -```csharp -namespace MySpace -{ - public class MyClass {} - - public class Foo - { - public void Bar() - { - var baz = new MyClass(); - } - } -} - -public class Qux -{ - public void Box() - { - var nux = new MySpace.MyClass(); - } -} - -namespace OtherSpace -{ - using MySpace; - - public class Tix - { - public void Jeg() - { - var lor = new MyClass(); - } - } -} -``` - -This [article][using] clearly explains the ways in which the `using` directive can be used: - -- `using`: avoid having to qualify types with namespace -- `using static`: avoid having to qualify members with types (a good example is `Math.Max()`). -- `using MyAlias = YourNamespace;`: substitute a more readable name for the namespace name. - -#### Clash of namespaces - -.NET addresses the issue of two namespaces with the same name in different assemblies where there would be a clash of fully qualified identifier names (perhaps a scenario where multiple versions of an assembly are loaded). This issue is addressed with the [namespace alias qualifier][namespace-alias-qualifier] and the [extern alias][extern-alias]. - -One reason to raise this fairly niche topic is because of its use of the [`::` operator][dot-dot-operator]. You will often see the qualifier `global::` prefixing namespaces, particularly in generated code. The intention here is to avoid a potential clash with some nested namespace or class name. By prefixing a namespace with `global::` you ensure that a top-level namespace is selected. - -#### Note for Java developers - -When comparing with the `import` of Java `packages` some differences and similarities should be noted: - -- There is no equivalent with C# of importing specific types. -- `using static` and `import static` are equivalent. -- In Java, package names have an impact on accessibility as between jars. In C# assemblies are paramount and belonging to the same namespace does not affect access level. -- The relationship between file system paths and fully qualified class names in Java is not reflected in C#'s namespaces although it is good practice where possible to give a file the same name as the principal class it contains. - -#### Reference - -- [Namespaces][namespaces]: how to define and import namespaces. -- [Accessibility levels][accessibility-levels]: use the `public/internal/private` access modifiers. - -[namespaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/namespaces/ -[accessibility-levels]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/accessibility-levels -[namespace-alias-qualifier]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier -[extern-alias]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias -[using]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive -[assemblies]: https://docs.microsoft.com/en-us/dotnet/standard/assembly/ -[dot-dot-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/namespace-alias-qualifier From 592a66cfc4efaa040a7124125e4a5a07b8923210 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:17:36 +0200 Subject: [PATCH 230/327] nested-types - replace about.md file with concept files * Pre-populate nested-types concept's about.md file from after.md file * Pre-populate nested-types concept's links.json file from after.md file * nested-types - Remove after.md document * Update about.md Co-authored-by: Mike May --- concepts/nested-types/about.md | 105 ++++++++++++++++- concepts/nested-types/links.json | 7 +- exercises/concept/nested-types/.docs/after.md | 108 ------------------ 3 files changed, 110 insertions(+), 110 deletions(-) delete mode 100644 exercises/concept/nested-types/.docs/after.md diff --git a/concepts/nested-types/about.md b/concepts/nested-types/about.md index 13bf1fa073..c0f7dce25a 100644 --- a/concepts/nested-types/about.md +++ b/concepts/nested-types/about.md @@ -1 +1,104 @@ -TODO: add information on nested-types concept +C# types can be defined within the scope of a class or struct. The enclosing type provides a kind name space. Access to the type is through the enclosing type with dot syntax. + +```csharp +class Outer +{ + public interface IInner {} + public enum EInner {} + public class CInner {} + public struct SInner {} +} + +var outer = new Outer(); +var inner = new Outer.CInner(); +``` + +#### Access levels + +Access levels can be applied to the inner types. For example if a class is `private` then it cannot be seen outside of the enclosing type's scope and of course instances cannot be seen or used outside the scope. + +The private members of the outer class are in scope for all the members of the inner class but only the non-private members of the inner class are in scope for the members of the outer class. In order to access the outer classes members the inner class has to be given an instance of the outer class. + +This can be seen in the following example: + +```csharp +class Outer +{ + public class InnerImpl + { + private Outer outer; + + public int Interesting = 42; + + public InnerImpl(Outer outer, int interesting) + { + this.outer = outer; + Interesting = interesting; + } + + } + + public InnerImpl Inner; + public Outer() + { + Inner = new InnerImpl(this, 42); + } +} + +var outer = new Outer(); +outer.Inner.Interesting +// => 42 +var inner = new Outer.InnerImpl(outer, 1729); +outer.Inner.Interesting +// => 1729 +``` + +#### Prevent independent instantiation + +There is a pattern to prevent an instantiable type being created outside the enclosing type. You expose a public interface but keep the implementing class private. + +```csharp +class Outer +{ + public interface IInner + { + void DoSomething(); + } + + private class InnerImpl : IInner + { + private Outer outer; + public InnerImpl(Outer outer) + { + this.outer = outer; + } + public void DoSomething() + { + outer.DoSomethingElse(); + } + } + + public IInner Inner; + + public Outer() + { + Inner = new InnerImpl(this); + } + private void DoSomethingElse() + { + } +} + +var outer = new Outer(); +outer.Inner.DoSomething(); + +// NOT var inner = new Outer.Inner(outer); +``` + +#### Note for Java developers + +C#'s nested classes are a cross between Java's static nested classes and inner classes. In C# private members of the enclosing class are in scope for members of the nested class but there is no special syntax for instantiating them and linking them to an instance of the enclosing class. You have to use some variation of the pattern illustrated in the examples above. + +C# does have static nested classes, but these are simply enclosed classes with static behavior. + +[nested-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types diff --git a/concepts/nested-types/links.json b/concepts/nested-types/links.json index fe51488c70..410a52b9aa 100644 --- a/concepts/nested-types/links.json +++ b/concepts/nested-types/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types", + "description": "nested-types" + } +] diff --git a/exercises/concept/nested-types/.docs/after.md b/exercises/concept/nested-types/.docs/after.md deleted file mode 100644 index b48de2b025..0000000000 --- a/exercises/concept/nested-types/.docs/after.md +++ /dev/null @@ -1,108 +0,0 @@ -C# types can be defined within the scope of a class or struct. The enclosing type provides a kind name space. Access to the type is through the enclosing type with dot syntax. - -```csharp -class Outer -{ - public interface IInner {} - public enum EInner {} - public class CInner {} - public struct SInner {} -} - -var outer = new Outer(); -var inner = new Outer.CInner(); -``` - -#### Access levels - -Access levels can be applied to the inner types. For example if a class is `private` then it cannot be seen outside of the enclosing type's scope and of course instances cannot be seen or used outside the scope. - -The private members of the outer class are in scope for all the members of the inner class but only the non-private members of the inner class are in scope for the members of the outer class. In order to access the outer classes members the inner class has to be given an instance of the outer class. - -This can be seen in the following example: - -```csharp -class Outer -{ - public class InnerImpl - { - private Outer outer; - - public int Interesting = 42; - - public InnerImpl(Outer outer, int interesting) - { - this.outer = outer; - Interesting = interesting; - } - - } - - public InnerImpl Inner; - public Outer() - { - Inner = new InnerImpl(this, 42); - } -} - -var outer = new Outer(); -outer.Inner.Interesting -// => 42 -var inner = new Outer.InnerImpl(outer, 1729); -outer.Inner.Interesting -// => 1729 -``` - -#### Prevent independent instantiation - -There is a pattern to prevent an instantiable type being created outside the enclosing type. You expose a public interface but keep the implementing class private. - -```csharp -class Outer -{ - public interface IInner - { - void DoSomething(); - } - - private class InnerImpl : IInner - { - private Outer outer; - public InnerImpl(Outer outer) - { - this.outer = outer; - } - public void DoSomething() - { - outer.DoSomethingElse(); - } - } - - public IInner Inner; - - public Outer() - { - Inner = new InnerImpl(this); - } - private void DoSomethingElse() - { - } -} - -var outer = new Outer(); -outer.Inner.DoSomething(); - -// NOT var inner = new Outer.Inner(outer); -``` - -#### Note for Java developers - -C#'s nested classes are a cross between Java's static nested classes and inner classes. In C# private members of the enclosing class are in scope for members of the nested class but there is no special syntax for instantiating them and linking them to an instance of the enclosing class. You have to use some variation of the pattern illustrated in the examples above. - -C# does have static nested classes, but these are simply enclosed classes with static behavior. - -#### Reference - -This documentation of [nested types][nested-types] details the syntax. - -[nested-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types From dc603f67a5b9d62166160b13c48eef6678e3ff77 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:17:49 +0200 Subject: [PATCH 231/327] numbers - replace about.md file with concept files * Pre-populate if-statements concept's about.md file from after.md file * Pre-populate if-statements concept's links.json file from after.md file * Pre-populate numbers concept's about.md file from after.md file * Pre-populate numbers concept's links.json file from after.md file * numbers - Remove after.md document * Update about.md * Update links.json * Update about.md Co-authored-by: Mike May --- concepts/if-statements/about.md | 19 ++++++- concepts/numbers/about.md | 54 +++++++++++++++++- concepts/numbers/links.json | 19 ++++++- exercises/concept/numbers/.docs/after.md | 72 ------------------------ 4 files changed, 89 insertions(+), 75 deletions(-) delete mode 100644 exercises/concept/numbers/.docs/after.md diff --git a/concepts/if-statements/about.md b/concepts/if-statements/about.md index 7f6fbf8015..e256153118 100644 --- a/concepts/if-statements/about.md +++ b/concepts/if-statements/about.md @@ -1 +1,18 @@ -TODO: add information on if-statements concept +An `if` statement can be used to conditionally execute code. The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values. + +```csharp +int x = 6; + +if (x == 5) +{ + // Execute logic if x equals 5 +} +else if (x > 7) +{ + // Execute logic if x greater than 7 +} +else +{ + // Execute logic in all other cases +} +``` diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md index 36eb002377..c16655f886 100644 --- a/concepts/numbers/about.md +++ b/concepts/numbers/about.md @@ -1 +1,53 @@ -TODO: add information on numbers concept +One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). + +The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). + +```csharp +int i = 123; +double d = 54.29; +``` + +Both integers and floating-point numbers can use the `_` character as a _digit separator_, which can help when defining large numbers: + +```csharp +int largeInt = 1_000_000; +// => 1000000 + +double largeDouble = 9_876_543.21; +// => 9876543.21 +``` + +Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.) and the [equality-][equality-operators] operator (`==`) and [inequality][equality-operators] operator (`!=`). + +```csharp +5 * 6; +// => 30 + +1.2 > 0.8 +// => true + +2 != 4 +// => true +``` + +When converting between numeric types, there are two types of numeric conversions: + +1. Implicit conversions: no data will be lost and no additional syntax is required. +2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. + +As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. + +```csharp +int i = 9; +double d = 2.66; + +// Safe conversion, thus implicit conversion +double fromInt = i; + +// Potentially unsafe conversion, thus explicit conversion +int fromDouble = (int)d; +``` + +[arithmetic-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators +[equality-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators +[comparison-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators diff --git a/concepts/numbers/links.json b/concepts/numbers/links.json index fe51488c70..6be94a9c60 100644 --- a/concepts/numbers/links.json +++ b/concepts/numbers/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators", + "description": "arithmetic-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators", + "description": "comparison-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators", + "description": "equality-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators", + "description": "equality-operators" + } +] diff --git a/exercises/concept/numbers/.docs/after.md b/exercises/concept/numbers/.docs/after.md deleted file mode 100644 index 6b0d8dfe92..0000000000 --- a/exercises/concept/numbers/.docs/after.md +++ /dev/null @@ -1,72 +0,0 @@ -One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator). - -The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number). - -```csharp -int i = 123; -double d = 54.29; -``` - -Both integers and floating-point numbers can use the `_` character as a _digit separator_, which can help when defining large numbers: - -```csharp -int largeInt = 1_000_000; -// => 1000000 - -double largeDouble = 9_876_543.21; -// => 9876543.21 -``` - -Arithmetic is done using the standard [arithmetic operators][arithmetic-operators] (`+`, `-`, `*`, etc.). Numbers can be compared using the standard [comparison operators][comparison-operators] (`<`, `>=`, etc.) and the [equality-][equality-operators] operator (`==`) and [inequality][equality-operators] operator (`!=`). - -```csharp -5 * 6; -// => 30 - -1.2 > 0.8 -// => true - -2 != 4 -// => true -``` - -When converting between numeric types, there are two types of numeric conversions: - -1. Implicit conversions: no data will be lost and no additional syntax is required. -2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required. - -As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. - -```csharp -int i = 9; -double d = 2.66; - -// Safe conversion, thus implicit conversion -double fromInt = i; - -// Potentially unsafe conversion, thus explicit conversion -int fromDouble = (int)d; -``` - -An `if` statement can be used to conditionally execute code. The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values. - -```csharp -int x = 6; - -if (x == 5) -{ - // Execute logic if x equals 5 -} -else if (x > 7) -{ - // Execute logic if x greater than 7 -} -else -{ - // Execute logic in all other cases -} -``` - -[arithmetic-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators -[equality-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/equality-operators -[comparison-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/comparison-operators From de13661c5c40f71c1e962a2004aeb660cd5cca4a Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 11:18:07 +0200 Subject: [PATCH 232/327] overflow - replace about.md file with concept files * Pre-populate overflow concept's about.md file from after.md file * Pre-populate overflow concept's links.json file from after.md file * overflow - Remove after.md document * Update about.md Co-authored-by: Mike May --- concepts/overflow/about.md | 50 ++++++++++++++++++- concepts/overflow/links.json | 59 ++++++++++++++++++++++- exercises/concept/overflow/.docs/after.md | 57 ---------------------- 3 files changed, 107 insertions(+), 59 deletions(-) delete mode 100644 exercises/concept/overflow/.docs/after.md diff --git a/concepts/overflow/about.md b/concepts/overflow/about.md index 9ca01eb292..72f48e559f 100644 --- a/concepts/overflow/about.md +++ b/concepts/overflow/about.md @@ -1 +1,49 @@ -TODO: add information on overflow concept +The exercise shows the behavior of various numeric types when they overflow, i.e. when their capacity is insufficient to contain the value resulting from a computation such as an arithmetic operation or cast. + +- unsigned [integers][integral-numeric-types] (`byte`, `ushort`, `uint`, `ulong`) will wrap around to zero (the type's maximum value + 1 acts as a modulus) unless [broadly speaking][checked-compiler-setting] they appear within a [`checked`][checked-and-unchecked] block in which case an instance of `OverflowException` is thrown. `int` and `long` will behave similarly except that they wrap around to `int.MinValue` and `long.minValue` respectively. + +```csharp +int one = 1; +checked +{ + int expr = int.MaxValue + one; // overflow exception is thrown +} + +// or + +int expr2 = checked(int.MaxValue + one); // overflow exception is thrown +``` + +- If a literal expression would cause the variable to which it is assigned to overflow then a compile-time error occurs. +- the `checked` state applies only to expressions directly in the block. Overflow states in called functions are not caught. +- [`float` and `double`][floating-point-numeric-types] types will adopt a state of _infinity_ that can be tested wtih `float.IsInfinity()` etc. + +```csharp +double d = double.MaxValue; +d *= 2d; +Double.IsFinite(d) +// => false +``` + +- Numbers of type [`decimal`][floating-point-numeric-types] will cause an instance of `OverflowException` to be thrown. +- There is a corresponding `unchecked` keyword for circumstances where you want to reverse the effect of `unchecked` inside a `checked` block or when the compiler setting has been used. + +Overflows that occur without an exception being thrown can be problematic because it's generally true that the earlier an error condition can be reported the better. + +Problems with overflows for `int` and `float` can be mitigated by assigning the result to a variable of type `long`, `decimal` or `double`. + +If large integers are essential to your code then using the [`BigInteger`][big-integer] type is an option. + +Naturally there are occasions on which it is legitimate to allow an integer to wrap around particularly in the case of unsigned values. A classic case is that of hash codes that use the width of the integer as a kind of modulo. + +You will usually find in code bases that there is often no check where an `uint` or a `ulong` is used as an identifier because it is considered more trouble than it's worth. This also applies where it is evident from the domain that no very large values will be involved. But, look at [this][computerphile-gangnam-style] for a cautionary tale. + +[computerphile-gangnam-style]: https://www.youtube.com/watch?v=vA0Rl6Ne5C8 +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[checked-and-unchecked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked +[checked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked +[unchecked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unchecked +[checked-compiler-setting]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/checked-compiler-option +[big-integer]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netcore-3.1 diff --git a/concepts/overflow/links.json b/concepts/overflow/links.json index fe51488c70..e4665fcc36 100644 --- a/concepts/overflow/links.json +++ b/concepts/overflow/links.json @@ -1 +1,58 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types", + "description": "integral-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/checked-compiler-option", + "description": "checked-compiler-setting" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked", + "description": "checked-and-unchecked" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types", + "description": "floating-point-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types", + "description": "floating-point-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netcore-3.1", + "description": "big-integer" + }, + { + "url": "https://www.youtube.com/watch?v=vA0Rl6Ne5C8", + "description": "computerphile-gangnam-style" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types", + "description": "integral-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types", + "description": "floating-point-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions", + "description": "numeric-conversions" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked", + "description": "checked-and-unchecked" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked", + "description": "checked-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unchecked", + "description": "unchecked-keyword" + }, + { + "url": "https://www.youtube.com/watch?v=vA0Rl6Ne5C8", + "description": "computerphile-gangnam-style" + } +] diff --git a/exercises/concept/overflow/.docs/after.md b/exercises/concept/overflow/.docs/after.md deleted file mode 100644 index 27f8730aa9..0000000000 --- a/exercises/concept/overflow/.docs/after.md +++ /dev/null @@ -1,57 +0,0 @@ -The exercise shows the behavior of various numeric types when they overflow, i.e. when their capacity is insufficient to contain the value resulting from a computation such as an arithmetic operation or cast. - -- unsigned [integers][integral-numeric-types] (`byte`, `ushort`, `uint`, `ulong`) will wrap around to zero (the type's maximum value + 1 acts as a modulus) unless [broadly speaking][checked-compiler-setting] they appear within a [`checked`][checked-and-unchecked] block in which case an instance of `OverflowException` is thrown. `int` and `long` will behave similarly except that they wrap around to `int.MinValue` and `long.minValue` respectively. - -```csharp -int one = 1; -checked -{ - int expr = int.MaxValue + one; // overflow exception is thrown -} - -// or - -int expr2 = checked(int.MaxValue + one); // overflow exception is thrown -``` - -- If a literal expression would cause the variable to which it is assigned to overflow then a compile-time error occurs. -- the `checked` state applies only to expressions directly in the block. Overflow states in called functions are not caught. -- [`float` and `double`][floating-point-numeric-types] types will adopt a state of _infinity_ that can be tested wtih `float.IsInfinity()` etc. - -```csharp -double d = double.MaxValue; -d *= 2d; -Double.IsFinite(d) -// => false -``` - -- Numbers of type [`decimal`][floating-point-numeric-types] will cause an instance of `OverflowException` to be thrown. -- There is a corresponding `unchecked` keyword for circumstances where you want to reverse the effect of `unchecked` inside a `checked` block or when the compiler setting has been used. - -Overflows that occur without an exception being thrown can be problematic because it's generally true that the earlier an error condition can be reported the better. - -Problems with overflows for `int` and `float` can be mitigated by assigning the result to a variable of type `long`, `decimal` or `double`. - -If large integers are essential to your code then using the [`BigInteger`][big-integer] type is an option. - -Naturally there are occasions on which it is legitimate to allow an integer to wrap around particularly in the case of unsigned values. A classic case is that of hash codes that use the width of the integer as a kind of modulo. - -You will usually find in code bases that there is often no check where an `uint` or a `ulong` is used as an identifier because it is considered more trouble than it's worth. This also applies where it is evident from the domain that no very large values will be involved. But, look at [this][computerphile-gangnam-style] for a cautionary tale. - -- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. -- [Floating-point numeric types][floating-point-numeric-types]: overview of the floating-point numeric types. -- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. -- [Checked and unchecked arithmetic][checked-and-unchecked]: introduction to overflows -- [`checked` keyword][checked-keyword]: `checked` keyword reference. -- [`unchecked` keyword][unchecked-keyword]: `unchecked` keyword reference. -- [Computerphile: How Gangnam Style broke YouTube][computerphile-gangnam-style] - -[computerphile-gangnam-style]: https://www.youtube.com/watch?v=vA0Rl6Ne5C8 -[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types -[floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types -[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions -[checked-and-unchecked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked -[checked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked -[unchecked-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/unchecked -[checked-compiler-setting]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/checked-compiler-option -[big-integer]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger?view=netcore-3.1 From d4d9030f1040e6bbcc190543d408a0863b8037a4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 14:41:26 +0200 Subject: [PATCH 233/327] interfaces - replace about.md file with concept files * Pre-populate interfaces concept's about.md file from after.md file * Pre-populate interfaces concept's links.json file from after.md file * Pre-populate ordering concept's about.md file from after.md file * Pre-populate ordering concept's links.json file from after.md file * interfaces - Remove after.md document * Update about.md * Update links.json Co-authored-by: Mike May --- concepts/interfaces/about.md | 183 +++++++++++++++++++- concepts/interfaces/links.json | 43 ++++- exercises/concept/interfaces/.docs/after.md | 182 ------------------- 3 files changed, 224 insertions(+), 184 deletions(-) delete mode 100644 exercises/concept/interfaces/.docs/after.md diff --git a/concepts/interfaces/about.md b/concepts/interfaces/about.md index 5463e9d03a..771fe01c66 100644 --- a/concepts/interfaces/about.md +++ b/concepts/interfaces/about.md @@ -1 +1,182 @@ -TODO: add information on interfaces concept +[`interfaces`][interfaces] are the primary means of [decoupling][wiki-loose-coupling] the uses of a class from its implementation. This decoupling provides flexibility for maintenance of the implementation and helps support type safe generic behavior. + +The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided. + +```csharp +public interface ILanguage +{ + string Speak(); +} + +public interface IItalianLanguage : ILanguage +{ + string Speak(); + string SpeakItalian(); +} + +public interface IScriptConverter +{ + string Version { get; set; } + string ConvertCyrillicToLatin(string cyrillic); +} +``` + +The implementing class or struct must implement all operations defined by the interface. + +Interfaces typically do one or more of the following: + +- allow a number of different classes to be treated generically by the using code. In this case interfaces are playing the same role as a base class +- expose a subset of functionality for some specific purpose (such as [`IComparable`][icomparable]) or +- expose the public API of a class so that multiple implementations can co-exist. One example is that of a [test double][wiki-test-double] + +```csharp +public class ItalianTraveller : IItalianLanguage +{ + public string Speak() + { + return "Ciao mondo"; + } + + public string SpeakItalian() + { + return Speak(); + } +} + +public class ItalianTravellerV2 : IItalianLanguage +{ + public string Speak() + { + return "migliorata - Ciao mondo"; + } + + public string SpeakItalian() + { + return Speak(); + } +} + +public class FrenchTraveller : ILanguage +{ + public string Speak() + { + return "Ça va?"; + } +} + +public class RussianTraveller : ILanguage, IScriptConverter +{ + public string Version { get; set; } = "1.0"; + + public string Speak() + { + return "Привет мир"; + } + + public string ConvertCyrillicToLatin(string cyrillic) + { + throw new NotImplementedException(); + } +} + +public class DocumentTranslator : IScriptConverter +{ + public string Version { get; set; } = "1.0"; + + public string Translate(string russian) + { + throw new NotImplementedException(); + } + + public string ConvertCyrillicToLatin(string cyrillic) + { + throw new NotImplementedException(); + } +} +``` + +Code which uses the above interfaces and classes can: + +- treat all speakers in the same way irrespective of language. +- allow some subsystem handling script conversion to operate without caring about what specific types it is dealing with. +- remain unaware of the changes to the italian speaker which is convenient if the class code and user code are maintained by different teams + +Interfaces are widely used to support testing as they allow for easy [mocking][so-mocking-interfaces]. + +See this [article][dt-interfaces] for details of what types of member can be included in an interface. + +Interfaces can inherit from other interfaces. + +Members of an interface are public by default. + +Interfaces can contain nested types, such as `const` literals, `enums`, `delegates`, `classes` and `structs`. Here, the interfaces act as [namespaces][wiki-namespaces] in the same way that classes and structs do and the behaviour and syntax is identical. + +By design, C# does not support multiple inheritance, but it facilitates a kind of multiple inheritance through interfaces. + +Moreover, the concept of [polymorphism can be implemented through interfaces][interface-polymorphism] underpins the interface mechanism. + +#### Explicit interface implementation + +Sometimes method names and signatures can be shared in two different interfaces. +In order provide a distinct implementation of these methods, C# provides [explicit implementation of interfaces][explicit-implementation]. Note that to use a particular implementation of an interface you need to convert the expression containing referencing the object to that interface. Assignment, casting or passing as a parameter will achieve this. + +```csharp +public interface IFoo +{ + void X(); +} + +public interface IBar +{ + void X(); +} + +public class Census : IFoo, IBar +{ + void IFoo.X() + { + Console.Write("This is from Foo"); + } + + void IBar.X() + { + Console.Write("This is from Bar"); + } +} + +public class User +{ + public void Use() + { + IFoo foo = new Census(); + IBar bar = new Census(); + foo.X(); + // => "This is from Foo" + bar.X(); + // => "This is from Bar" + } +} +``` + +There are a number of use cases: + +- A clash of domains (as illustrated above) where methods have identical signatures. +- Methods with the same name but different return types: if you implement your own collection classes you may find that an explicit interface for the legacy `IEnumerable.GetEnumerator()`, alongside `IEnumerable.GetEnuerator()`, is required. You may never make use of such the interface but the compiler may insist. +- Methods where there is no clash of names between interfaces but it is desirable that the implementing class uses the name for some related purpose: `IFormattable` has a `ToString()` method which takes a _format type_ parameter as well as parameter of type `IFormatProvider`. A class like `FormattableString` from the Base Class Library (BCL) has the interface to ensure it can be used by routines that take an `IFormattable` but it is more expressive for its main version of `ToString(IFormatProvider)` to omit the _format type_ parameter as it is not used in the implementation and would confuse API users. + +#### Default implementation + +Version 8 of C# addresses a nagging problem with APIs. If you add methods to an interface to enhance functionality for new implementations then it is necessary to modify all the existing implementations of the interface so that they comply with the API-contract even though they have no implementation specific behavior. C# now allows for a _default method_ to be provided as part of the interface (Java developers will be familiar). Previously, when such a change occurred a _version 2_ of the interface would exist alongside the original. + +This [article][dt-interfaces] is an excellent primer on interfaces and focuses on _default implementation_ and other supporting innovations such as `static`, `private` and `virtual` members. + +[interface-polymorphism]: https://www.cs.utexas.edu/~mitra/csSummer2013/cs312/lectures/interfaces.html +[explicit-implementation]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation +[so-mocking-interfaces]: https://stackoverflow.com/a/9226437/96167 +[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 +[wiki-test-double]: https://en.wikipedia.org/wiki/Test_double +[wiki-polymorphism]: https://en.wikipedia.org/wiki/Polymorphism_(computer_science) +[wiki-namespaces]: https://en.wikipedia.org/wiki/Namespace +[dt-interfaces]: https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/ +[wiki-loose-coupling]: https://en.wikipedia.org/wiki/Loose_coupling +[interfaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ diff --git a/concepts/interfaces/links.json b/concepts/interfaces/links.json index fe51488c70..928b1ecdcb 100644 --- a/concepts/interfaces/links.json +++ b/concepts/interfaces/links.json @@ -1 +1,42 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/", + "description": "interfaces" + }, + { + "url": "https://en.wikipedia.org/wiki/Loose_coupling", + "description": "wiki-loose-coupling" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1", + "description": "icomparable" + }, + { + "url": "https://en.wikipedia.org/wiki/Test_double", + "description": "wiki-test-double" + }, + { + "url": "https://stackoverflow.com/a/9226437/96167", + "description": "so-mocking-interfaces" + }, + { + "url": "https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/", + "description": "dt-interfaces" + }, + { + "url": "https://en.wikipedia.org/wiki/Namespace", + "description": "wiki-namespaces" + }, + { + "url": "https://www.cs.utexas.edu/~mitra/csSummer2013/cs312/lectures/interfaces.html", + "description": "interface-polymorphism" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation", + "description": "explicit-implementation" + }, + { + "url": "https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/", + "description": "dt-interfaces" + } +] diff --git a/exercises/concept/interfaces/.docs/after.md b/exercises/concept/interfaces/.docs/after.md deleted file mode 100644 index 771fe01c66..0000000000 --- a/exercises/concept/interfaces/.docs/after.md +++ /dev/null @@ -1,182 +0,0 @@ -[`interfaces`][interfaces] are the primary means of [decoupling][wiki-loose-coupling] the uses of a class from its implementation. This decoupling provides flexibility for maintenance of the implementation and helps support type safe generic behavior. - -The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided. - -```csharp -public interface ILanguage -{ - string Speak(); -} - -public interface IItalianLanguage : ILanguage -{ - string Speak(); - string SpeakItalian(); -} - -public interface IScriptConverter -{ - string Version { get; set; } - string ConvertCyrillicToLatin(string cyrillic); -} -``` - -The implementing class or struct must implement all operations defined by the interface. - -Interfaces typically do one or more of the following: - -- allow a number of different classes to be treated generically by the using code. In this case interfaces are playing the same role as a base class -- expose a subset of functionality for some specific purpose (such as [`IComparable`][icomparable]) or -- expose the public API of a class so that multiple implementations can co-exist. One example is that of a [test double][wiki-test-double] - -```csharp -public class ItalianTraveller : IItalianLanguage -{ - public string Speak() - { - return "Ciao mondo"; - } - - public string SpeakItalian() - { - return Speak(); - } -} - -public class ItalianTravellerV2 : IItalianLanguage -{ - public string Speak() - { - return "migliorata - Ciao mondo"; - } - - public string SpeakItalian() - { - return Speak(); - } -} - -public class FrenchTraveller : ILanguage -{ - public string Speak() - { - return "Ça va?"; - } -} - -public class RussianTraveller : ILanguage, IScriptConverter -{ - public string Version { get; set; } = "1.0"; - - public string Speak() - { - return "Привет мир"; - } - - public string ConvertCyrillicToLatin(string cyrillic) - { - throw new NotImplementedException(); - } -} - -public class DocumentTranslator : IScriptConverter -{ - public string Version { get; set; } = "1.0"; - - public string Translate(string russian) - { - throw new NotImplementedException(); - } - - public string ConvertCyrillicToLatin(string cyrillic) - { - throw new NotImplementedException(); - } -} -``` - -Code which uses the above interfaces and classes can: - -- treat all speakers in the same way irrespective of language. -- allow some subsystem handling script conversion to operate without caring about what specific types it is dealing with. -- remain unaware of the changes to the italian speaker which is convenient if the class code and user code are maintained by different teams - -Interfaces are widely used to support testing as they allow for easy [mocking][so-mocking-interfaces]. - -See this [article][dt-interfaces] for details of what types of member can be included in an interface. - -Interfaces can inherit from other interfaces. - -Members of an interface are public by default. - -Interfaces can contain nested types, such as `const` literals, `enums`, `delegates`, `classes` and `structs`. Here, the interfaces act as [namespaces][wiki-namespaces] in the same way that classes and structs do and the behaviour and syntax is identical. - -By design, C# does not support multiple inheritance, but it facilitates a kind of multiple inheritance through interfaces. - -Moreover, the concept of [polymorphism can be implemented through interfaces][interface-polymorphism] underpins the interface mechanism. - -#### Explicit interface implementation - -Sometimes method names and signatures can be shared in two different interfaces. -In order provide a distinct implementation of these methods, C# provides [explicit implementation of interfaces][explicit-implementation]. Note that to use a particular implementation of an interface you need to convert the expression containing referencing the object to that interface. Assignment, casting or passing as a parameter will achieve this. - -```csharp -public interface IFoo -{ - void X(); -} - -public interface IBar -{ - void X(); -} - -public class Census : IFoo, IBar -{ - void IFoo.X() - { - Console.Write("This is from Foo"); - } - - void IBar.X() - { - Console.Write("This is from Bar"); - } -} - -public class User -{ - public void Use() - { - IFoo foo = new Census(); - IBar bar = new Census(); - foo.X(); - // => "This is from Foo" - bar.X(); - // => "This is from Bar" - } -} -``` - -There are a number of use cases: - -- A clash of domains (as illustrated above) where methods have identical signatures. -- Methods with the same name but different return types: if you implement your own collection classes you may find that an explicit interface for the legacy `IEnumerable.GetEnumerator()`, alongside `IEnumerable.GetEnuerator()`, is required. You may never make use of such the interface but the compiler may insist. -- Methods where there is no clash of names between interfaces but it is desirable that the implementing class uses the name for some related purpose: `IFormattable` has a `ToString()` method which takes a _format type_ parameter as well as parameter of type `IFormatProvider`. A class like `FormattableString` from the Base Class Library (BCL) has the interface to ensure it can be used by routines that take an `IFormattable` but it is more expressive for its main version of `ToString(IFormatProvider)` to omit the _format type_ parameter as it is not used in the implementation and would confuse API users. - -#### Default implementation - -Version 8 of C# addresses a nagging problem with APIs. If you add methods to an interface to enhance functionality for new implementations then it is necessary to modify all the existing implementations of the interface so that they comply with the API-contract even though they have no implementation specific behavior. C# now allows for a _default method_ to be provided as part of the interface (Java developers will be familiar). Previously, when such a change occurred a _version 2_ of the interface would exist alongside the original. - -This [article][dt-interfaces] is an excellent primer on interfaces and focuses on _default implementation_ and other supporting innovations such as `static`, `private` and `virtual` members. - -[interface-polymorphism]: https://www.cs.utexas.edu/~mitra/csSummer2013/cs312/lectures/interfaces.html -[explicit-implementation]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/explicit-interface-implementation -[so-mocking-interfaces]: https://stackoverflow.com/a/9226437/96167 -[icomparable]: https://docs.microsoft.com/en-us/dotnet/api/system.icomparable-1?view=netcore-3.1 -[wiki-test-double]: https://en.wikipedia.org/wiki/Test_double -[wiki-polymorphism]: https://en.wikipedia.org/wiki/Polymorphism_(computer_science) -[wiki-namespaces]: https://en.wikipedia.org/wiki/Namespace -[dt-interfaces]: https://www.talkingdotnet.com/default-implementations-in-interfaces-in-c-sharp-8/ -[wiki-loose-coupling]: https://en.wikipedia.org/wiki/Loose_coupling -[interfaces]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/interfaces/ From a8443f801220c16e68cd9ef6e0ff5f7f23ca5689 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 14:42:22 +0200 Subject: [PATCH 234/327] integral-numbers - replace about.md file with concept files * Pre-populate integral-numbers concept's about.md file from after.md file * Pre-populate integral-numbers concept's links.json file from after.md file * integral-numbers - Remove after.md document --- concepts/integral-numbers/about.md | 91 ++++++++++++++++++- concepts/integral-numbers/links.json | 31 ++++++- .../concept/integral-numbers/.docs/after.md | 90 ------------------ 3 files changed, 120 insertions(+), 92 deletions(-) delete mode 100644 exercises/concept/integral-numbers/.docs/after.md diff --git a/concepts/integral-numbers/about.md b/concepts/integral-numbers/about.md index 9d9295732e..a233472422 100644 --- a/concepts/integral-numbers/about.md +++ b/concepts/integral-numbers/about.md @@ -1 +1,90 @@ -TODO: add information on integral-numbers concept +C#, like many statically typed languages, provides a number of types that represent integers, each with its own [range of values][integral-numeric-types]. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types. + +Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1. + +Values of unsigned integral types are represented with a simple [base 2][wiki-binary] representation. Values of signed types use [2s complement][wiki-twos-complement] signed number representation. + +The multiplicity of integer types reflects machine architectures, in the size of registers, the size of CPU instruction arguments and the treatment of sign within the CPU. A value of type `long` uses 64 bits whereas a value of type `sbyte` uses 8 bits. In some cases there will be implications on CPU performance, memory usage and even disk usage (where selection of a smaller integer type will generally be beneficial). Selection of integer `type` can also be a rough and ready wsy of communicating information to other developers about the expected range of values. The `int` type is widely used as the default type where nothing special has been identified about the particular usage. The `long` or `ulong` is widely used as a simple identifier. The size of the type in bytes determines the range of values. + +The types discussed so far are _primitive_ types. Each is paired with a `struct` alias which implements fields (such as `MinValue`) and methods (such as `ToString()`) which are associated with the type. + +| Type | Struct | Width | Minimum | Maximum | +| -------- | -------- | ------ | -------------------------- | --------------------------- | +| `sbyte` | `SByte` | 8 bit | -128 | +127 | +| `short` | `Int16` | 16 bit | -32_768 | +32_767 | +| `int` | `Int32` | 32 bit | -2_147_483_648 | +2_147_483_647 | +| `long` | `Int64` | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 | +| `byte` | `Byte` | 8 bit | 0 | +255 | +| `ushort` | `UInt16` | 16 bit | 0 | +65_535 | +| `uint` | `UInt32` | 32 bit | 0 | +4_294_967_295 | +| `ulong` | `UInt64` | 64 bit | 0 | +18_446_744_073_709_551_615 | + +#### Casting + +A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (rhs) ensures that the value will fit within the range of the type being assigned to (lhs) then there is a simple assignment: + +```csharp +ulong ul; +uint ui = uint.MaxValue; +ul = ui; // no problem +``` + +On the other hand if the range of type being assigned from is not a subset of the assignee's range of values then a cast, `()` operation is required even if the particular value is within the assignee's range: + +```csharp +uint ui; +short s = 42; +ui = (uint)s; +``` + +In the above example, if the value lay instead outside the range of the assignee then an overflow would occur. See (TODO cross-ref-tba). + +The requirement for casting is determined by the two types involved rather than a particular value. + +The following paragraphs discuss the casting of integral types. (TODO cross-ref-tba casting) provides a broader discussion of casting and type conversion. See that documentation for a discussion of conversion between integral types and floating-point numbers, `char` and `bool`. + +##### Casting Primitive Types - Implicit + +C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. + +An implicit cast is not signified by any special syntax. + +##### Casting Primitive Types - Explicit + +Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. + +Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown. + +#### Casting Primitive Types - Examples + +```csharp +int largeInt = Int32.MaxValue; +int largeNegInt = Int32.MinValue; +ushort shortUnsignedInt = ushort.MaxValue; + +// implicit cast +int from_ushort = shortUnsignedInt; // 65535 +float from_int = largeInt; // -21474836E+09 + +// explicit cast +uint from_largeInt = (uint)largeInt; // 2147483647 +uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) + +``` + +#### Bit conversion + +The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes. + +#### Reference + +- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. +- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. + +[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types +[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression +[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[wiki-twos-complement]: https://en.wikipedia.org/wiki/Two%27s_complement +[wiki-binary]: https://en.wikipedia.org/wiki/Binary_number +[sbyte]: https://docs.microsoft.com/en-us/dotnet/api/system.sbyte?view=netcore-3.1 diff --git a/concepts/integral-numbers/links.json b/concepts/integral-numbers/links.json index fe51488c70..2ff988fcd8 100644 --- a/concepts/integral-numbers/links.json +++ b/concepts/integral-numbers/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types", + "description": "integral-numeric-types" + }, + { + "url": "https://en.wikipedia.org/wiki/Binary_number", + "description": "wiki-binary" + }, + { + "url": "https://en.wikipedia.org/wiki/Two%27s_complement", + "description": "wiki-twos-complement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions", + "description": "implicit-casts" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression", + "description": "cast-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types", + "description": "integral-numeric-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions", + "description": "numeric-conversions" + } +] diff --git a/exercises/concept/integral-numbers/.docs/after.md b/exercises/concept/integral-numbers/.docs/after.md deleted file mode 100644 index a233472422..0000000000 --- a/exercises/concept/integral-numbers/.docs/after.md +++ /dev/null @@ -1,90 +0,0 @@ -C#, like many statically typed languages, provides a number of types that represent integers, each with its own [range of values][integral-numeric-types]. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types. - -Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1. - -Values of unsigned integral types are represented with a simple [base 2][wiki-binary] representation. Values of signed types use [2s complement][wiki-twos-complement] signed number representation. - -The multiplicity of integer types reflects machine architectures, in the size of registers, the size of CPU instruction arguments and the treatment of sign within the CPU. A value of type `long` uses 64 bits whereas a value of type `sbyte` uses 8 bits. In some cases there will be implications on CPU performance, memory usage and even disk usage (where selection of a smaller integer type will generally be beneficial). Selection of integer `type` can also be a rough and ready wsy of communicating information to other developers about the expected range of values. The `int` type is widely used as the default type where nothing special has been identified about the particular usage. The `long` or `ulong` is widely used as a simple identifier. The size of the type in bytes determines the range of values. - -The types discussed so far are _primitive_ types. Each is paired with a `struct` alias which implements fields (such as `MinValue`) and methods (such as `ToString()`) which are associated with the type. - -| Type | Struct | Width | Minimum | Maximum | -| -------- | -------- | ------ | -------------------------- | --------------------------- | -| `sbyte` | `SByte` | 8 bit | -128 | +127 | -| `short` | `Int16` | 16 bit | -32_768 | +32_767 | -| `int` | `Int32` | 32 bit | -2_147_483_648 | +2_147_483_647 | -| `long` | `Int64` | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807 | -| `byte` | `Byte` | 8 bit | 0 | +255 | -| `ushort` | `UInt16` | 16 bit | 0 | +65_535 | -| `uint` | `UInt32` | 32 bit | 0 | +4_294_967_295 | -| `ulong` | `UInt64` | 64 bit | 0 | +18_446_744_073_709_551_615 | - -#### Casting - -A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (rhs) ensures that the value will fit within the range of the type being assigned to (lhs) then there is a simple assignment: - -```csharp -ulong ul; -uint ui = uint.MaxValue; -ul = ui; // no problem -``` - -On the other hand if the range of type being assigned from is not a subset of the assignee's range of values then a cast, `()` operation is required even if the particular value is within the assignee's range: - -```csharp -uint ui; -short s = 42; -ui = (uint)s; -``` - -In the above example, if the value lay instead outside the range of the assignee then an overflow would occur. See (TODO cross-ref-tba). - -The requirement for casting is determined by the two types involved rather than a particular value. - -The following paragraphs discuss the casting of integral types. (TODO cross-ref-tba casting) provides a broader discussion of casting and type conversion. See that documentation for a discussion of conversion between integral types and floating-point numbers, `char` and `bool`. - -##### Casting Primitive Types - Implicit - -C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. - -An implicit cast is not signified by any special syntax. - -##### Casting Primitive Types - Explicit - -Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. - -Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown. - -#### Casting Primitive Types - Examples - -```csharp -int largeInt = Int32.MaxValue; -int largeNegInt = Int32.MinValue; -ushort shortUnsignedInt = ushort.MaxValue; - -// implicit cast -int from_ushort = shortUnsignedInt; // 65535 -float from_int = largeInt; // -21474836E+09 - -// explicit cast -uint from_largeInt = (uint)largeInt; // 2147483647 -uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) - -``` - -#### Bit conversion - -The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes. - -#### Reference - -- [Integral numeric types][integral-numeric-types]: overview of the integral numeric types. -- [Numeric conversions][numeric-conversions]: overview of implicit and explicit numeric conversions. - -[integral-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types -[numeric-conversions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions -[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression -[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions -[wiki-twos-complement]: https://en.wikipedia.org/wiki/Two%27s_complement -[wiki-binary]: https://en.wikipedia.org/wiki/Binary_number -[sbyte]: https://docs.microsoft.com/en-us/dotnet/api/system.sbyte?view=netcore-3.1 From 026d9c3a3021d826e6ff6be6e2f6338a3171b998 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 14:43:05 +0200 Subject: [PATCH 235/327] inheritance - replace about.md file with concept files * Pre-populate inheritance concept's about.md file from after.md file * Pre-populate inheritance concept's links.json file from after.md file * inheritance - Remove after.md document --- concepts/inheritance/about.md | 79 +++++++++++++++++++- concepts/inheritance/links.json | 43 ++++++++++- exercises/concept/inheritance/.docs/after.md | 78 ------------------- 3 files changed, 120 insertions(+), 80 deletions(-) delete mode 100644 exercises/concept/inheritance/.docs/after.md diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md index 8d36c90764..7ba8e9ef9c 100644 --- a/concepts/inheritance/about.md +++ b/concepts/inheritance/about.md @@ -1 +1,78 @@ -TODO: add information on inheritance concept +In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. + +Parent classes can provide functionality to derived classes in three ways: + +- Define a regular method. +- Define a [`virtual` method][virtual-keyword], which is like a regular method but one that derived classes _can_ change. +- Define an [`abstract` method][abstract-keyword], which is a method without an implementation that derived classes _must_ implement. A class with `abstract` methods must be marked as [`abstract`][abstract-classes] too. Abstract classes cannot be instantiated. + +The [`protected` access modifier][protected-keyword] allows a parent class member to be accessed in a derived class, but blocks access from other classes. Derived classes thus can access `public` and `protected` parent class members, but not `private` parent class members. + +Derived classes can access parent class members through the [`base` keyword][base-keyword]. + +```csharp +// Inherits from the 'object' class +abstract class Vehicle +{ + // Can be overridden + public virtual void Drive() + { + } + + // Must be overridden + protected abstract int Speed(); +} + +// Cannot be inherited from +sealed class Car : Vehicle +{ + public override void Drive() + { + // Override virtual method + + // Call parent implementation + base.Drive(); + } + + protected override int Speed() + { + // Implement abstract method + } +} +``` + +The constructor of a derived class will [automatically call its parent's constructor][constructors] _before_ executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the [`base` keyword][base-keyword-constructor]. As abstract classes cannot be instantiated, their constructors can be made `protected`. + +```csharp +abstract class Vehicle +{ + protected Vehicle(int wheels) + { + Console.WriteLine("Called first"); + } +} + +class Car : Vehicle +{ + public Car() : base(4) + { + Console.WriteLine("Called second"); + } +} +``` + +To prevent a class being inherited, add the [`sealed` modifier][sealed-classes]. +Some practitioners try to avoid inheriting from concrete classes (as discussed in [this SO question][pro-sealed]) and the _sealed_ modifier supports this approach. On the other hand many C# developers consider them a hindrance to maintenance as discussed in some of the comments on [this question][anti-sealed]. The advice is to use the sealed modifier sparingly until you have gained confidence in their use for your requirements. + +[abstract-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract +[virtual-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual +[override-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override +[base-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base +[base-keyword-constructor]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base#example-1 +[protected-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected +[sealed-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed +[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors +[abstract-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#abstract-classes-and-class-members +[sealed-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members +[pro-sealed]: https://stackoverflow.com/questions/16724946/why-derive-from-a-concrete-class-is-a-poor-design +[anti-sealed]: https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class diff --git a/concepts/inheritance/links.json b/concepts/inheritance/links.json index fe51488c70..e7785c8ac3 100644 --- a/concepts/inheritance/links.json +++ b/concepts/inheritance/links.json @@ -1 +1,42 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual", + "description": "virtual-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract", + "description": "abstract-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#abstract-classes-and-class-members", + "description": "abstract-classes" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected", + "description": "protected-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base", + "description": "base-keyword" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors", + "description": "constructors" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base#example-1", + "description": "base-keyword-constructor" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members", + "description": "sealed-classes" + }, + { + "url": "https://stackoverflow.com/questions/16724946/why-derive-from-a-concrete-class-is-a-poor-design", + "description": "pro-sealed" + }, + { + "url": "https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class", + "description": "anti-sealed" + } +] diff --git a/exercises/concept/inheritance/.docs/after.md b/exercises/concept/inheritance/.docs/after.md deleted file mode 100644 index 7ba8e9ef9c..0000000000 --- a/exercises/concept/inheritance/.docs/after.md +++ /dev/null @@ -1,78 +0,0 @@ -In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. - -Parent classes can provide functionality to derived classes in three ways: - -- Define a regular method. -- Define a [`virtual` method][virtual-keyword], which is like a regular method but one that derived classes _can_ change. -- Define an [`abstract` method][abstract-keyword], which is a method without an implementation that derived classes _must_ implement. A class with `abstract` methods must be marked as [`abstract`][abstract-classes] too. Abstract classes cannot be instantiated. - -The [`protected` access modifier][protected-keyword] allows a parent class member to be accessed in a derived class, but blocks access from other classes. Derived classes thus can access `public` and `protected` parent class members, but not `private` parent class members. - -Derived classes can access parent class members through the [`base` keyword][base-keyword]. - -```csharp -// Inherits from the 'object' class -abstract class Vehicle -{ - // Can be overridden - public virtual void Drive() - { - } - - // Must be overridden - protected abstract int Speed(); -} - -// Cannot be inherited from -sealed class Car : Vehicle -{ - public override void Drive() - { - // Override virtual method - - // Call parent implementation - base.Drive(); - } - - protected override int Speed() - { - // Implement abstract method - } -} -``` - -The constructor of a derived class will [automatically call its parent's constructor][constructors] _before_ executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the [`base` keyword][base-keyword-constructor]. As abstract classes cannot be instantiated, their constructors can be made `protected`. - -```csharp -abstract class Vehicle -{ - protected Vehicle(int wheels) - { - Console.WriteLine("Called first"); - } -} - -class Car : Vehicle -{ - public Car() : base(4) - { - Console.WriteLine("Called second"); - } -} -``` - -To prevent a class being inherited, add the [`sealed` modifier][sealed-classes]. -Some practitioners try to avoid inheriting from concrete classes (as discussed in [this SO question][pro-sealed]) and the _sealed_ modifier supports this approach. On the other hand many C# developers consider them a hindrance to maintenance as discussed in some of the comments on [this question][anti-sealed]. The advice is to use the sealed modifier sparingly until you have gained confidence in their use for your requirements. - -[abstract-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract -[virtual-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual -[override-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override -[base-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base -[base-keyword-constructor]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/base#example-1 -[protected-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/protected -[sealed-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/sealed -[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors -[abstract-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#abstract-classes-and-class-members -[sealed-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members -[pro-sealed]: https://stackoverflow.com/questions/16724946/why-derive-from-a-concrete-class-is-a-poor-design -[anti-sealed]: https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class From 511c09da7d68a1712905d0afa5bdf50801d30c99 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:30:24 +0200 Subject: [PATCH 236/327] exceptions - replace about.md file with concept files * Pre-populate exceptions concept's about.md file from after.md file * exceptions - Remove after.md document --- concepts/exceptions/about.md | 10 +++++++++- exercises/concept/exceptions/.docs/after.md | 9 --------- 2 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 exercises/concept/exceptions/.docs/after.md diff --git a/concepts/exceptions/about.md b/concepts/exceptions/about.md index 98dcbc456c..2dd4d9e2d4 100644 --- a/concepts/exceptions/about.md +++ b/concepts/exceptions/about.md @@ -1 +1,9 @@ -TODO: add information on exceptions concept +It is important to note that `exceptions` should be used in cases where something exceptional happens, an error that needs special handeling. It should not be used for control-flow of a program, as that is considered bad design, which often leads to bad performance and maintainability. + +Some of the more common exceptions include `IndexOutOfRangeException`, `ArgumentOutOfRangeException`, `NullReferenceException`, `StackOverflowException`, `ArgumentException`, `InvalidOperationException` and `DivideByZeroException`. + +Some of the cases when exceptions should be thrown include: + +- if the method cannot complete its defined functionality +- an inappropriate call to an object is made, based on the object state +- when an argument to a method causes an exception diff --git a/exercises/concept/exceptions/.docs/after.md b/exercises/concept/exceptions/.docs/after.md deleted file mode 100644 index 2dd4d9e2d4..0000000000 --- a/exercises/concept/exceptions/.docs/after.md +++ /dev/null @@ -1,9 +0,0 @@ -It is important to note that `exceptions` should be used in cases where something exceptional happens, an error that needs special handeling. It should not be used for control-flow of a program, as that is considered bad design, which often leads to bad performance and maintainability. - -Some of the more common exceptions include `IndexOutOfRangeException`, `ArgumentOutOfRangeException`, `NullReferenceException`, `StackOverflowException`, `ArgumentException`, `InvalidOperationException` and `DivideByZeroException`. - -Some of the cases when exceptions should be thrown include: - -- if the method cannot complete its defined functionality -- an inappropriate call to an object is made, based on the object state -- when an argument to a method causes an exception From 56f1d6f2e9eee84ca71c4d5da8f16c70715c812f Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:38:03 +0200 Subject: [PATCH 237/327] dictionaries - replace about.md file with concept files * Pre-populate dictionaries concept's about.md file from after.md file * Pre-populate dictionaries concept's links.json file from after.md file * dictionaries - Remove after.md document --- concepts/dictionaries/about.md | 32 ++++++++++++++++++- concepts/dictionaries/links.json | 31 +++++++++++++++++- exercises/concept/dictionaries/.docs/after.md | 31 ------------------ 3 files changed, 61 insertions(+), 33 deletions(-) delete mode 100644 exercises/concept/dictionaries/.docs/after.md diff --git a/concepts/dictionaries/about.md b/concepts/dictionaries/about.md index e68f19fc89..90fb70e4ea 100644 --- a/concepts/dictionaries/about.md +++ b/concepts/dictionaries/about.md @@ -1 +1,31 @@ -TODO: add information on dictionaries concept +Dictionaries, like their equivalents in other languages such as maps or associative arrays, store key/value pairs such that a value can be retrieved or changed directly by passing the key to the dictionary's indexer property. + +In addition key/value pairs can be added and removed from the dictionary. Keys, values and key/value pairs can be enumerated. + +Values can be objects of any C# type, which includes primitives, structs _and_ classes. + +The Dictionary object allows keys to be objects of any type. However to ensure correct behavior at runtime keys must have an appropriate hashcode as returned by [GetHashCode][gethashcode]. + +A dictionary instance cannot be safely accessed by more than one thread (not thread-safe). [ConcurrentDictionary][concurrent-dictionary] is available for multi-threading situations. + +See also [HashSet][hashset], [ConcurrentDictionary][concurrent-dictionary], [SortedDictionary][sorted-dictionary]. + +Whilst there is no non-generic version of Dictionary a number of classes remain in the library to support a non-generic map. You need to be aware of the non-generic IDictionary and Hashtable mainly so that you know them when you see them. It is unlikely you would have to use them other than in maintaining an old code base. + +You will often want to expose and access the dictionary by its [`IDictionary`][idictionary] interface. + +Note that because of the nature of [indexer properties][indexer-properties] primitive values can be modified in place, such as: + +```csharp +nums["some-number"] = 3; +nums["some-number"]++; +// nums["some-number"] == 4 + +``` + +[concurrent-dictionary]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-3.1 +[hashset]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[gethashcode]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 +[sorted-dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netcore-3.1 +[idictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.idictionary-2?view=netcore-3.1 +[indexer-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/ diff --git a/concepts/dictionaries/links.json b/concepts/dictionaries/links.json index fe51488c70..f872747f47 100644 --- a/concepts/dictionaries/links.json +++ b/concepts/dictionaries/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1", + "description": "gethashcode" + }, + { + "url": "https://docs.microsoft.com/en-gb/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-3.1", + "description": "concurrent-dictionary" + }, + { + "url": "https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1", + "description": "hashset" + }, + { + "url": "https://docs.microsoft.com/en-gb/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-3.1", + "description": "concurrent-dictionary" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netcore-3.1", + "description": "sorted-dictionary" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.idictionary-2?view=netcore-3.1", + "description": "idictionary" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/", + "description": "indexer-properties" + } +] diff --git a/exercises/concept/dictionaries/.docs/after.md b/exercises/concept/dictionaries/.docs/after.md deleted file mode 100644 index 90fb70e4ea..0000000000 --- a/exercises/concept/dictionaries/.docs/after.md +++ /dev/null @@ -1,31 +0,0 @@ -Dictionaries, like their equivalents in other languages such as maps or associative arrays, store key/value pairs such that a value can be retrieved or changed directly by passing the key to the dictionary's indexer property. - -In addition key/value pairs can be added and removed from the dictionary. Keys, values and key/value pairs can be enumerated. - -Values can be objects of any C# type, which includes primitives, structs _and_ classes. - -The Dictionary object allows keys to be objects of any type. However to ensure correct behavior at runtime keys must have an appropriate hashcode as returned by [GetHashCode][gethashcode]. - -A dictionary instance cannot be safely accessed by more than one thread (not thread-safe). [ConcurrentDictionary][concurrent-dictionary] is available for multi-threading situations. - -See also [HashSet][hashset], [ConcurrentDictionary][concurrent-dictionary], [SortedDictionary][sorted-dictionary]. - -Whilst there is no non-generic version of Dictionary a number of classes remain in the library to support a non-generic map. You need to be aware of the non-generic IDictionary and Hashtable mainly so that you know them when you see them. It is unlikely you would have to use them other than in maintaining an old code base. - -You will often want to expose and access the dictionary by its [`IDictionary`][idictionary] interface. - -Note that because of the nature of [indexer properties][indexer-properties] primitive values can be modified in place, such as: - -```csharp -nums["some-number"] = 3; -nums["some-number"]++; -// nums["some-number"] == 4 - -``` - -[concurrent-dictionary]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.concurrent.concurrentdictionary-2?view=netcore-3.1 -[hashset]: https://docs.microsoft.com/en-gb/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 -[gethashcode]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 -[sorted-dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.sorteddictionary-2?view=netcore-3.1 -[idictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.idictionary-2?view=netcore-3.1 -[indexer-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/ From 08455fd1958c9487f5e434a9da0b5389bb2d8056 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:39:03 +0200 Subject: [PATCH 238/327] datetimes - replace about.md file with concept files * Pre-populate datetimes concept's about.md file from after.md file * Pre-populate datetimes concept's links.json file from after.md file * datetimes - Remove after.md document --- concepts/datetimes/about.md | 14 +++++++++++++- concepts/datetimes/links.json | 19 ++++++++++++++++++- exercises/concept/datetimes/.docs/after.md | 13 ------------- 3 files changed, 31 insertions(+), 15 deletions(-) delete mode 100644 exercises/concept/datetimes/.docs/after.md diff --git a/concepts/datetimes/about.md b/concepts/datetimes/about.md index 3bc9842e1b..d92f0b6f52 100644 --- a/concepts/datetimes/about.md +++ b/concepts/datetimes/about.md @@ -1 +1,13 @@ -TODO: add information on datetimes concept +A `DateTime` in C# is an immutable object that contains both date _and_ time information. The date and time information can be accessed through its built-in [properties][properties]. + +Manipulating a `DateTime` can be done by calling one of its [methods][methods]. As `DateTime` values can never change after having been defined, all methods that appear to modify a `DateTime` will actually return a new `DateTime`. + +Comparing `DateTime` instances can be done using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the `DateTime.Now` property. + +An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s will be dependent on the current culture. This includes the [`DateTime.Parse()` method][parse] that parses a `string` to a `DateTime`, as well as the `DateTime` class' [`ToString()` method][to-string] that converts a `DateTime` to a `string`. + +[parse]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netcore-3.1#System_DateTime_Parse_System_String_ +[operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#operators +[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#properties +[to-string]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=netcore-3.1 +[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#methods diff --git a/concepts/datetimes/links.json b/concepts/datetimes/links.json index fe51488c70..23a8625eab 100644 --- a/concepts/datetimes/links.json +++ b/concepts/datetimes/links.json @@ -1 +1,18 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#properties", + "description": "properties" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#methods", + "description": "methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netcore-3.1#System_DateTime_Parse_System_String_", + "description": "parse" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=netcore-3.1", + "description": "to-string" + } +] diff --git a/exercises/concept/datetimes/.docs/after.md b/exercises/concept/datetimes/.docs/after.md deleted file mode 100644 index d92f0b6f52..0000000000 --- a/exercises/concept/datetimes/.docs/after.md +++ /dev/null @@ -1,13 +0,0 @@ -A `DateTime` in C# is an immutable object that contains both date _and_ time information. The date and time information can be accessed through its built-in [properties][properties]. - -Manipulating a `DateTime` can be done by calling one of its [methods][methods]. As `DateTime` values can never change after having been defined, all methods that appear to modify a `DateTime` will actually return a new `DateTime`. - -Comparing `DateTime` instances can be done using the default comparison operators (`<`, `>`, etc.). The current date (and time) can be retrieved through the `DateTime.Now` property. - -An important aspect of dates in C# is that they are culture-dependent. As such, any `DateTime` method that deals with `string`s will be dependent on the current culture. This includes the [`DateTime.Parse()` method][parse] that parses a `string` to a `DateTime`, as well as the `DateTime` class' [`ToString()` method][to-string] that converts a `DateTime` to a `string`. - -[parse]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.parse?view=netcore-3.1#System_DateTime_Parse_System_String_ -[operators]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#operators -[properties]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#properties -[to-string]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring?view=netcore-3.1 -[methods]: https://docs.microsoft.com/en-us/dotnet/api/system.datetime?view=netcore-3.1#methods From 10e4a34d67f600481cf44896d7f7d85141706fdc Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:40:04 +0200 Subject: [PATCH 239/327] constructors - replace about.md file with concept files * Pre-populate constructors concept's about.md file from after.md file * Pre-populate constructors concept's links.json file from after.md file * constructors - Remove after.md document --- concepts/constructors/about.md | 74 ++++++++++++++++++- concepts/constructors/links.json | 23 +++++- exercises/concept/constructors/.docs/after.md | 73 ------------------ 3 files changed, 95 insertions(+), 75 deletions(-) delete mode 100644 exercises/concept/constructors/.docs/after.md diff --git a/concepts/constructors/about.md b/concepts/constructors/about.md index e4368b7dff..ca5bb2aeda 100644 --- a/concepts/constructors/about.md +++ b/concepts/constructors/about.md @@ -1 +1,73 @@ -TODO: add information on constructors concept +Creating an instance of a _class_ is done by calling its [_constructor_][constructors] through the [`new` operator][new]. A constructor is a special type of method whose goal is to initialize a newly created instance. [Constructors look like regular methods][constructor-syntax], but without a return type and with a name that matches the classes' name. + +```csharp +class Library +{ + private books; + + public Library() + { + this.books = 10; + } +} + +// This will call the constructor +var library = new Library(); +``` + +Like regular methods, constructors can have parameters. Constructor parameters are usually stored as (private) [fields][fields] to be accessed later, or else used in some one-off calculation. Arguments can be passed to constructors just like passing arguments to regular methods. + +```csharp +class Building +{ + private int numberOfStories; + private int totalHeight; + + public Building(int numberOfStories, double storyHeight) + { + this.numberOfStories = numberOfStories; + this.totalHeight = numberOfStories * storyHeight; + } +} + +// Call a constructor with two arguments +var largeBuilding = new Building(55, 6.2) +``` + +Specifying a constructor is optional. If no constructor is specified, a [parameterless constructor][parameterless-constructors] is generated by the compiler: + +```csharp +class Elevator +{ +} + +// This will call the (empty) generated constructor +var elevator = new Elevator(); +``` + +If fields have an initial value assigned to them, the compiler will output code in which the assignment is actually done inside the constructor. The following class declarations are thus equivalent (functionality-wise): + +```csharp +class UsingFieldInitialization +{ + private int players = 5; +} + +class UsingConstructorInitialization +{ + private int players; + + public UsingConstructorInitialization() + { + players = 5; + } +} +``` + +[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors +[constructor-syntax]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax +[using-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors +[private-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/private-constructors +[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[parameterless-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#parameterless-constructors diff --git a/concepts/constructors/links.json b/concepts/constructors/links.json index fe51488c70..6a9d2bef2c 100644 --- a/concepts/constructors/links.json +++ b/concepts/constructors/links.json @@ -1 +1,22 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors", + "description": "constructors" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator", + "description": "new" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax", + "description": "constructor-syntax" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields", + "description": "fields" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#parameterless-constructors", + "description": "parameterless-constructors" + } +] diff --git a/exercises/concept/constructors/.docs/after.md b/exercises/concept/constructors/.docs/after.md deleted file mode 100644 index ca5bb2aeda..0000000000 --- a/exercises/concept/constructors/.docs/after.md +++ /dev/null @@ -1,73 +0,0 @@ -Creating an instance of a _class_ is done by calling its [_constructor_][constructors] through the [`new` operator][new]. A constructor is a special type of method whose goal is to initialize a newly created instance. [Constructors look like regular methods][constructor-syntax], but without a return type and with a name that matches the classes' name. - -```csharp -class Library -{ - private books; - - public Library() - { - this.books = 10; - } -} - -// This will call the constructor -var library = new Library(); -``` - -Like regular methods, constructors can have parameters. Constructor parameters are usually stored as (private) [fields][fields] to be accessed later, or else used in some one-off calculation. Arguments can be passed to constructors just like passing arguments to regular methods. - -```csharp -class Building -{ - private int numberOfStories; - private int totalHeight; - - public Building(int numberOfStories, double storyHeight) - { - this.numberOfStories = numberOfStories; - this.totalHeight = numberOfStories * storyHeight; - } -} - -// Call a constructor with two arguments -var largeBuilding = new Building(55, 6.2) -``` - -Specifying a constructor is optional. If no constructor is specified, a [parameterless constructor][parameterless-constructors] is generated by the compiler: - -```csharp -class Elevator -{ -} - -// This will call the (empty) generated constructor -var elevator = new Elevator(); -``` - -If fields have an initial value assigned to them, the compiler will output code in which the assignment is actually done inside the constructor. The following class declarations are thus equivalent (functionality-wise): - -```csharp -class UsingFieldInitialization -{ - private int players = 5; -} - -class UsingConstructorInitialization -{ - private int players; - - public UsingConstructorInitialization() - { - players = 5; - } -} -``` - -[constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors -[constructor-syntax]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#constructor-syntax -[using-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors -[private-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/private-constructors -[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator -[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields -[parameterless-constructors]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constructors#parameterless-constructors From cfdf670c38602d0ec315e0ef15b4f51b39493498 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:51:40 +0200 Subject: [PATCH 240/327] classes - replace about.md file with concept files * Pre-populate classes concept's about.md file from after.md file * Pre-populate classes concept's links.json file from after.md file * classes - Remove after.md document --- concepts/classes/about.md | 101 ++++++++++++++++++++++- concepts/classes/links.json | 51 +++++++++++- exercises/concept/classes/.docs/after.md | 100 ---------------------- 3 files changed, 150 insertions(+), 102 deletions(-) delete mode 100644 exercises/concept/classes/.docs/after.md diff --git a/concepts/classes/about.md b/concepts/classes/about.md index 608d2f539e..d254869203 100644 --- a/concepts/classes/about.md +++ b/concepts/classes/about.md @@ -1 +1,100 @@ -TODO: add information on classes concept +The primary object-oriented construct in C# is the _class_, which is a combination of data ([_fields_][fields]) and behavior ([_methods_][methods]). The fields and methods of a class are known as its _members_. + +Access to members can be restricted through access modifiers, the two most common ones being: + +- [`public`][public]: the member can be accessed by any code (no restrictions). +- [`private`][private]: the member can only be accessed by code in the same class. + +It is customary to specify an access modifier for all members. If no access modifier is specified, it will default to `private`. + +The above-mentioned grouping of related data and behavior plus restricting access to members is known as _encapsulation_, which is one of the core object-oriented concepts. + +You can think of a class as a template for creating instances of that class. To [create an instance of a class][creating-objects] (also known as an _object_), the [`new` keyword][new] is used: + +```csharp +class Car +{ +} + +// Create two car instances +var myCar = new Car(); +var yourCar = new Car(); +``` + +[Fields][fields] have a type and a name (defined in [camelCase][camel-case]) and can be defined anywhere in a class (defined in [PascalCase][pascal-case]). + +```csharp +class Car +{ + // Accessible by anyone + public int weight; + + // Only accessible by code in this class + private string color; +} +``` + +One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it will be set to its type's [default value][default-values]. An instance's field values can be accessed and updated using dot-notation. + +```csharp +class Car +{ + // Will be set to specified value + public int weight = 2500; + + // Will be set to default value (0) + public int year; +} + +var newCar = new Car(); +newCar.weight; // => 2500 +newCar.year; // => 0 + +// Update value of the field +newCar.year = 2018; +``` + +Private fields are usually updated as a side-effect of calling a method. Such methods usually don't return any value, in which case the return type should be [`void`][void]: + +```csharp +class CarImporter +{ + private int carsImported; + + public void ImportCars(int numberOfCars) + { + // Update private field + carsImported = carsImported + numberOfCars; + } +} +``` + +Note that is not customary to use public fields in C# classes. Either private fields are used or other types of members that will be discussed in subsequent exercises. + +Within a class, the [`this` keyword][this] will refer to the current class. This is especially useful if a parameter has the same name as a field: + +```csharp +class CarImporter +{ + private int carsImported; + + public void SetImportedCars(int carsImported) + { + // Update private field from public method + this.carsImported = carsImported; + } +} +``` + +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods +[this]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this +[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator +[void]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/void +[creating-objects]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#creating-objects +[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields +[public]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/public +[private]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private +[default-values]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values +[camel-case]: https://techterms.com/definition/camelcase +[pascal-case]: https://techterms.com/definition/pascalcase diff --git a/concepts/classes/links.json b/concepts/classes/links.json index fe51488c70..955a50beb2 100644 --- a/concepts/classes/links.json +++ b/concepts/classes/links.json @@ -1 +1,50 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields", + "description": "fields" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods", + "description": "methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/public", + "description": "public" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private", + "description": "private" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#creating-objects", + "description": "creating-objects" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator", + "description": "new" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields", + "description": "fields" + }, + { + "url": "https://techterms.com/definition/camelcase", + "description": "camel-case" + }, + { + "url": "https://techterms.com/definition/pascalcase", + "description": "pascal-case" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values", + "description": "default-values" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/void", + "description": "void" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this", + "description": "this" + } +] diff --git a/exercises/concept/classes/.docs/after.md b/exercises/concept/classes/.docs/after.md deleted file mode 100644 index d254869203..0000000000 --- a/exercises/concept/classes/.docs/after.md +++ /dev/null @@ -1,100 +0,0 @@ -The primary object-oriented construct in C# is the _class_, which is a combination of data ([_fields_][fields]) and behavior ([_methods_][methods]). The fields and methods of a class are known as its _members_. - -Access to members can be restricted through access modifiers, the two most common ones being: - -- [`public`][public]: the member can be accessed by any code (no restrictions). -- [`private`][private]: the member can only be accessed by code in the same class. - -It is customary to specify an access modifier for all members. If no access modifier is specified, it will default to `private`. - -The above-mentioned grouping of related data and behavior plus restricting access to members is known as _encapsulation_, which is one of the core object-oriented concepts. - -You can think of a class as a template for creating instances of that class. To [create an instance of a class][creating-objects] (also known as an _object_), the [`new` keyword][new] is used: - -```csharp -class Car -{ -} - -// Create two car instances -var myCar = new Car(); -var yourCar = new Car(); -``` - -[Fields][fields] have a type and a name (defined in [camelCase][camel-case]) and can be defined anywhere in a class (defined in [PascalCase][pascal-case]). - -```csharp -class Car -{ - // Accessible by anyone - public int weight; - - // Only accessible by code in this class - private string color; -} -``` - -One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it will be set to its type's [default value][default-values]. An instance's field values can be accessed and updated using dot-notation. - -```csharp -class Car -{ - // Will be set to specified value - public int weight = 2500; - - // Will be set to default value (0) - public int year; -} - -var newCar = new Car(); -newCar.weight; // => 2500 -newCar.year; // => 0 - -// Update value of the field -newCar.year = 2018; -``` - -Private fields are usually updated as a side-effect of calling a method. Such methods usually don't return any value, in which case the return type should be [`void`][void]: - -```csharp -class CarImporter -{ - private int carsImported; - - public void ImportCars(int numberOfCars) - { - // Update private field - carsImported = carsImported + numberOfCars; - } -} -``` - -Note that is not customary to use public fields in C# classes. Either private fields are used or other types of members that will be discussed in subsequent exercises. - -Within a class, the [`this` keyword][this] will refer to the current class. This is especially useful if a parameter has the same name as a field: - -```csharp -class CarImporter -{ - private int carsImported; - - public void SetImportedCars(int carsImported) - { - // Update private field from public method - this.carsImported = carsImported; - } -} -``` - -[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields -[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods -[this]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this -[new]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/new-operator -[void]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/void -[creating-objects]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#creating-objects -[fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields -[public]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/public -[private]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/private -[default-values]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values -[camel-case]: https://techterms.com/definition/camelcase -[pascal-case]: https://techterms.com/definition/pascalcase From 9399aa8d34382db94aabc45a2424ed1ebc614a61 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:53:20 +0200 Subject: [PATCH 241/327] flag-enums - replace about.md file with concept files * Pre-populate bit-manipulation concept's about.md file from after.md file * Pre-populate bit-manipulation concept's links.json file from after.md file * Pre-populate compound-assignment concept's about.md file from after.md file * Pre-populate compound-assignment concept's links.json file from after.md file * Pre-populate flag-enums concept's about.md file from after.md file * Pre-populate flag-enums concept's links.json file from after.md file * flag-enums - Remove after.md document * Update about.md * Update about.md * Update links.json * Update about.md * Update links.json * Update about.md * Update links.json * [CI] Format code Co-authored-by: Mike May Co-authored-by: github-actions[bot] --- concepts/bit-manipulation/about.md | 68 +++++++++++++++- concepts/bit-manipulation/links.json | 31 +++++++- concepts/compound-assignment/about.md | 11 ++- concepts/compound-assignment/links.json | 7 +- concepts/flag-enums/about.md | 80 ++++++++++++++++++- concepts/flag-enums/links.json | 31 +++++++- exercises/concept/flag-enums/.docs/after.md | 88 --------------------- 7 files changed, 222 insertions(+), 94 deletions(-) delete mode 100644 exercises/concept/flag-enums/.docs/after.md diff --git a/concepts/bit-manipulation/about.md b/concepts/bit-manipulation/about.md index f9f04742d0..44af0b9bbc 100644 --- a/concepts/bit-manipulation/about.md +++ b/concepts/bit-manipulation/about.md @@ -1 +1,67 @@ -TODO: add information on bit-manipulation concept +TODO: we need to reconsider the text below now that it is a stand alone concept or maybe bitwise manipulation should be introduced in a separate exercise and the flag-enums exercise and concept should take that as a dependency showing how bitwise manipulation is used in the context of enums. +To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags. + +```csharp +[Flags] +enum PhoneFeatures +{ + Call = 1, + Text = 2 +} +``` + +Besides using regular integers to set the flag enum members' values, one can also use [binary literals or the bitwise shift operator][binary-literals]. + +```csharp +[Flags] +enum PhoneFeaturesBinary +{ + Call = 0b00000001, + Text = 0b00000010 +} + +[Flags] +enum PhoneFeaturesBitwiseShift +{ + Call = 1 << 0, + Text = 1 << 1 +} +``` + +An enum member's value can refer to other enum members values: + +```csharp +[Flags] +enum PhoneFeatures +{ + Call = 0b00000001, + Text = 0b00000010, + All = Call | Text +} +``` + +Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. + +```csharp +var features = PhoneFeatures.Call; + +// Set the Text flag +features = features | PhoneFeatures.Text; + +features.HasFlag(PhoneFeatures.Call); // => true +features.HasFlag(PhoneFeatures.Text); // => true + +// Unset the Call flag +features = features & ~PhoneFeatures.Call; + +features.HasFlag(PhoneFeatures.Call); // => false +features.HasFlag(PhoneFeatures.Text); // => true +``` + +[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags +[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ +[or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- +[and-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator- +[bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- +[binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals +[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 diff --git a/concepts/bit-manipulation/links.json b/concepts/bit-manipulation/links.json index fe51488c70..8481c07e09 100644 --- a/concepts/bit-manipulation/links.json +++ b/concepts/bit-manipulation/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://riptutorial.com/csharp/example/6327/binary-literals", + "description": "binary-literals" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator-", + "description": "or-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator-", + "description": "and-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator-", + "description": "bitwise-complement-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1", + "description": "has-flag" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags", + "description": "docs.microsoft.com-enumeration-types-as-bit-flags" + }, + { + "url": "https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/", + "description": "alanzucconi.com-enum-flags-and-bitwise-operators" + } +] diff --git a/concepts/compound-assignment/about.md b/concepts/compound-assignment/about.md index 5fabff98d2..509b50ea59 100644 --- a/concepts/compound-assignment/about.md +++ b/concepts/compound-assignment/about.md @@ -1 +1,10 @@ -TODO: add information on compound-assignment concept +TODO: I think we need a different exercise to introduce compound assignments (one that shows it being used in a more conventional numeric or string context. flag-enums could then take that as a dependency and show how it is used in this more unusual context. +The bitwise operators can also be used as [compound assignments][compound-assignment], which are a shorthand notation where `x = op y` can be written as `x op= y`: + +```csharp +var features = PhoneFeatures.Call; +features |= PhoneFeatures.Text; +features &= ~PhoneFeatures.Call; +``` + +[compound-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment diff --git a/concepts/compound-assignment/links.json b/concepts/compound-assignment/links.json index fe51488c70..061dd8f1ff 100644 --- a/concepts/compound-assignment/links.json +++ b/concepts/compound-assignment/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment", + "description": "compound-assignment" + } +] diff --git a/concepts/flag-enums/about.md b/concepts/flag-enums/about.md index 78007cea97..0e597e9c3f 100644 --- a/concepts/flag-enums/about.md +++ b/concepts/flag-enums/about.md @@ -1 +1,79 @@ -TODO: add information on flag-enums concept +To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags. + +```csharp +[Flags] +enum PhoneFeatures +{ + Call = 1, + Text = 2 +} +``` + +Besides using regular integers to set the flag enum members' values, one can also use [binary literals or the bitwise shift operator][binary-literals]. + +```csharp +[Flags] +enum PhoneFeaturesBinary +{ + Call = 0b00000001, + Text = 0b00000010 +} + +[Flags] +enum PhoneFeaturesBitwiseShift +{ + Call = 1 << 0, + Text = 1 << 1 +} +``` + +An enum member's value can refer to other enum members values: + +```csharp +[Flags] +enum PhoneFeatures +{ + Call = 0b00000001, + Text = 0b00000010, + All = Call | Text +} +``` + +Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. + +```csharp +var features = PhoneFeatures.Call; + +// Set the Text flag +features = features | PhoneFeatures.Text; + +features.HasFlag(PhoneFeatures.Call); // => true +features.HasFlag(PhoneFeatures.Text); // => true + +// Unset the Call flag +features = features & ~PhoneFeatures.Call; + +features.HasFlag(PhoneFeatures.Call); // => false +features.HasFlag(PhoneFeatures.Text); // => true +``` + +The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. + +By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: + +```csharp +[Flags] +enum PhoneFeatures : byte +{ + Call = 0b00000001, + Text = 0b00000010 +} +``` + +[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags +[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ +[or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- +[and-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator- +[bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- +[binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals +[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 diff --git a/concepts/flag-enums/links.json b/concepts/flag-enums/links.json index fe51488c70..8481c07e09 100644 --- a/concepts/flag-enums/links.json +++ b/concepts/flag-enums/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://riptutorial.com/csharp/example/6327/binary-literals", + "description": "binary-literals" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator-", + "description": "or-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator-", + "description": "and-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator-", + "description": "bitwise-complement-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1", + "description": "has-flag" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags", + "description": "docs.microsoft.com-enumeration-types-as-bit-flags" + }, + { + "url": "https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/", + "description": "alanzucconi.com-enum-flags-and-bitwise-operators" + } +] diff --git a/exercises/concept/flag-enums/.docs/after.md b/exercises/concept/flag-enums/.docs/after.md deleted file mode 100644 index adcce2f28d..0000000000 --- a/exercises/concept/flag-enums/.docs/after.md +++ /dev/null @@ -1,88 +0,0 @@ -To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags. - -```csharp -[Flags] -enum PhoneFeatures -{ - Call = 1, - Text = 2 -} -``` - -Besides using regular integers to set the flag enum members' values, one can also use [binary literals or the bitwise shift operator][binary-literals]. - -```csharp -[Flags] -enum PhoneFeaturesBinary -{ - Call = 0b00000001, - Text = 0b00000010 -} - -[Flags] -enum PhoneFeaturesBitwiseShift -{ - Call = 1 << 0, - Text = 1 << 1 -} -``` - -An enum member's value can refer to other enum members values: - -```csharp -[Flags] -enum PhoneFeatures -{ - Call = 0b00000001, - Text = 0b00000010, - All = Call | Text -} -``` - -Setting a flag can be done through the [bitwise OR operator][or-operator] (`|`) and unsetting a flag through a combination of the [bitwise AND operator][and-operator] (`&`) and the [bitwise complement operator][bitwise-complement-operator] (`~`). While checking for a flag can be done through the bitwise AND operator, one can also use the enum's [`HasFlag()` method][has-flag]. - -```csharp -var features = PhoneFeatures.Call; - -// Set the Text flag -features = features | PhoneFeatures.Text; - -features.HasFlag(PhoneFeatures.Call); // => true -features.HasFlag(PhoneFeatures.Text); // => true - -// Unset the Call flag -features = features & ~PhoneFeatures.Call; - -features.HasFlag(PhoneFeatures.Call); // => false -features.HasFlag(PhoneFeatures.Text); // => true -``` - -The bitwise operators can also be used as [compound assignments][compound-assignment], which are a shorthand notation where `x = op y` can be written as `x op= y`: - -```csharp -var features = PhoneFeatures.Call; -features |= PhoneFeatures.Text; -features &= ~PhoneFeatures.Call; -``` - -The [working with enums as bit flags tutorial][docs.microsoft.com-enumeration-types-as-bit-flags] goes into more detail how to work with flag enums. Another great resource is the [enum flags and bitwise operators page][alanzucconi.com-enum-flags-and-bitwise-operators]. - -By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: - -```csharp -[Flags] -enum PhoneFeatures : byte -{ - Call = 0b00000001, - Text = 0b00000010 -} -``` - -[docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags -[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/ -[or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator- -[and-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator- -[bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator- -[binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals -[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1 -[compound-assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#compound-assignment From 149518b5710020c378a35269679676fdec20e3de Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:53:36 +0200 Subject: [PATCH 242/327] expression-bodied-members - replace about.md file with concept files * Pre-populate conditionals-ternary concept's about.md file from after.md file * Pre-populate conditionals-ternary concept's links.json file from after.md file * Pre-populate expression-bodied-members concept's about.md file from after.md file * Pre-populate expression-bodied-members concept's links.json file from after.md file * Pre-populate switch-expressions concept's about.md file from after.md file * Pre-populate switch-expressions concept's links.json file from after.md file * Pre-populate throw-expressions concept's about.md file from after.md file * Pre-populate throw-expressions concept's links.json file from after.md file * expression-bodied-members - Remove after.md document * Update about.md * Update links.json * Update about.md * Update links.json * Update about.md * Update links.json * Update about.md * Update links.json Co-authored-by: Mike May --- concepts/conditionals-ternary/about.md | 12 ++- concepts/conditionals-ternary/links.json | 7 +- concepts/expression-bodied-members/about.md | 12 ++- concepts/expression-bodied-members/links.json | 7 +- concepts/switch-expressions/about.md | 32 +++++++- concepts/switch-expressions/links.json | 15 +++- concepts/throw-expressions/about.md | 10 ++- concepts/throw-expressions/links.json | 7 +- .../expression-bodied-members/.docs/after.md | 74 ------------------- 9 files changed, 94 insertions(+), 82 deletions(-) delete mode 100644 exercises/concept/expression-bodied-members/.docs/after.md diff --git a/concepts/conditionals-ternary/about.md b/concepts/conditionals-ternary/about.md index 71e104bdb5..39e4720262 100644 --- a/concepts/conditionals-ternary/about.md +++ b/concepts/conditionals-ternary/about.md @@ -1 +1,11 @@ -TODO: add information on conditionals-ternary concept +[Ternary operators][ternary-operators] allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone. + +The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`). + +```csharp +int a = 3, b = 4; +int max = a > b ? a : b; +// => 4 +``` + +[ternary-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator diff --git a/concepts/conditionals-ternary/links.json b/concepts/conditionals-ternary/links.json index fe51488c70..435ac377bf 100644 --- a/concepts/conditionals-ternary/links.json +++ b/concepts/conditionals-ternary/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator", + "description": "ternary-operators" + } +] diff --git a/concepts/expression-bodied-members/about.md b/concepts/expression-bodied-members/about.md index 265512b866..8ee331576b 100644 --- a/concepts/expression-bodied-members/about.md +++ b/concepts/expression-bodied-members/about.md @@ -1 +1,11 @@ -TODO: add information on expression-bodied-members concept +Many [types of struct and class members][expression-bodied-members] (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements. + +```csharp +public int Times3(int input) => input * 3; + +public int Interesting => 1729; +``` + +Expression-bodied-members cannot have blocks of multiple statements, but those with a functional background should be warned that anything that a traditional member can do can be achieved by one of these members. The "expression" can be an assignment operation creating side effects, or a method invocation meaning that anything is possible. + +[expression-bodied-members]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members diff --git a/concepts/expression-bodied-members/links.json b/concepts/expression-bodied-members/links.json index fe51488c70..ca846ecfea 100644 --- a/concepts/expression-bodied-members/links.json +++ b/concepts/expression-bodied-members/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members", + "description": "expression-bodied-members" + } +] diff --git a/concepts/switch-expressions/about.md b/concepts/switch-expressions/about.md index 1ea714168d..fe814228ea 100644 --- a/concepts/switch-expressions/about.md +++ b/concepts/switch-expressions/about.md @@ -1 +1,31 @@ -TODO: add information on switch-expressions concept +[Switch expressions][switch-expressions] behave in a similar manner to [switch statements][switch-statements] covered in (TODO cross-ref-tba switch statements). They support a kind of decision table that maps input conditions to actions or values. + +At the core of the switch expression is _pattern matching_. In the coding exercise we matched values against `const` patterns. In this case the inputs to the `switch` are a _range expression_ which is matched to const values and the values used by the _case guards_. + +The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found. + +The `_` case which is the last in the list is useful to ensure that the matching is exhaustive and to avoid possible run-time errors. + +```csharp +double xx = 42d; + +string interesting = xx switch +{ + 0 => "I suppose zero is interesting", + 3.14 when DateTime.Now.Day == 14 && DateTime.Now.Month == 3 => "Mmm pie!", + 3.14 => "π", + 42 => "a bit of a cliché", + 1729 => "only if you are a pure mathematician", + _ => "not interesting" +}; + +// => interesting == "a bit of a cliché" +``` + +An "arm" of the `switch` is selected when the pattern matches the range variable and any case guard evaluates to true. + +Switch expression also support [type patterns][pattern-matching] and recursive matching. + +[switch-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression +[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#patterns-and-case-guards diff --git a/concepts/switch-expressions/links.json b/concepts/switch-expressions/links.json index fe51488c70..70d6b9d57a 100644 --- a/concepts/switch-expressions/links.json +++ b/concepts/switch-expressions/links.json @@ -1 +1,14 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression", + "description": "switch-expressions" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#patterns-and-case-guards", + "description": "pattern-matching" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members", + "description": "expression-bodied-members" + } +] diff --git a/concepts/throw-expressions/about.md b/concepts/throw-expressions/about.md index 22d112a032..ce681c08fb 100644 --- a/concepts/throw-expressions/about.md +++ b/concepts/throw-expressions/about.md @@ -1 +1,9 @@ -TODO: add information on throw-expressions concept +[`throw` expressions][throw-expressions] are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions. + +```csharp +string trimmed = str == null ? throw new ArgumentException() : str.Trim(); +``` + +If `str` is `null` in the above code an exception is thrown. + +[throw-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression diff --git a/concepts/throw-expressions/links.json b/concepts/throw-expressions/links.json index fe51488c70..096c5632a3 100644 --- a/concepts/throw-expressions/links.json +++ b/concepts/throw-expressions/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression", + "description": "throw-expressions" + } +] diff --git a/exercises/concept/expression-bodied-members/.docs/after.md b/exercises/concept/expression-bodied-members/.docs/after.md deleted file mode 100644 index 9af1699ba5..0000000000 --- a/exercises/concept/expression-bodied-members/.docs/after.md +++ /dev/null @@ -1,74 +0,0 @@ -Many [types of struct and class members][expression-bodied-members] (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements. - -```csharp -public int Times3(int input) => input * 3; - -public int Interesting => 1729; -``` - -Expression-bodied-members cannot have blocks of multiple statements, but those with a functional background should be warned that anything that a traditional member can do can be achieved by one of these members. The "expression" can be an assignment operation creating side effects, or a method invocation meaning that anything is possible. - -#### Ternary Operators - -[Ternary operators][ternary-operators] allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone. - -The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`). - -```csharp -int a = 3, b = 4; -int max = a > b ? a : b; -// => 4 -``` - -#### Switch expression - -[Switch expressions][switch-expressions] behave in a similar manner to [switch statements][switch-statements] covered in (TODO cross-ref-tba switch statements). They support a kind of decision table that maps input conditions to actions or values. - -At the core of the switch expression is _pattern matching_. In the coding exercise we matched values against `const` patterns. In this case the inputs to the `switch` are a _range expression_ which is matched to const values and the values used by the _case guards_. - -The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found. - -The `_` case which is the last in the list is useful to ensure that the matching is exhaustive and to avoid possible run-time errors. - -```csharp -double xx = 42d; - -string interesting = xx switch -{ - 0 => "I suppose zero is interesting", - 3.14 when DateTime.Now.Day == 14 && DateTime.Now.Month == 3 => "Mmm pie!", - 3.14 => "π", - 42 => "a bit of a cliché", - 1729 => "only if you are a pure mathematician", - _ => "not interesting" -}; - -// => interesting == "a bit of a cliché" -``` - -An "arm" of the `switch` is selected when the pattern matches the range variable and any case guard evaluates to true. - -Switch expression also support [type patterns][pattern-matching] and recursive matching. - -#### Throw expressions - -[`throw` expressions][throw-expressions] are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions. - -```csharp -string trimmed = str == null ? throw new ArgumentException() : str.Trim(); -``` - -If `str` is `null` in the above code an exception is thrown. - -#### Reference - -- [Expressions][expressions]: explains what expressions are. -- [Expression-bodied members][expression-bodied-members]: what expression-bodied members are and how to define them. - -[expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expressions -[expression-bodied-members]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members -[ternary-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/conditional-operator -[switch-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression -[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch -[pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#patterns-and-case-guards -[throw-expressions]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/throw#the-throw-expression From 9b4e34c411bf9fd3cea33f4feb4b4e7828992b3d Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:53:49 +0200 Subject: [PATCH 243/327] equality - replace about.md file with concept files * Pre-populate equality concept's about.md file from after.md file * Pre-populate equality concept's links.json file from after.md file * Pre-populate sets concept's about.md file from after.md file * Pre-populate sets concept's links.json file from after.md file * equality - Remove after.md document * Update about.md * Update about.md * Update links.json Co-authored-by: Mike May --- concepts/equality/about.md | 146 ++++++++++++++++++++- concepts/equality/links.json | 79 ++++++++++- exercises/concept/equality/.docs/after.md | 152 ---------------------- 3 files changed, 223 insertions(+), 154 deletions(-) delete mode 100644 exercises/concept/equality/.docs/after.md diff --git a/concepts/equality/about.md b/concepts/equality/about.md index 58de80ddcf..0c9e858ea9 100644 --- a/concepts/equality/about.md +++ b/concepts/equality/about.md @@ -1 +1,145 @@ -TODO: add information on equality concept +The coding exercise illustrates a number of properties of equality in C#: + +### `Object.Equals()` + +#### Topics covered by the coding exercise + +- Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. This is considered more idiomatic than using the [`Equals()`][object-equals] method which is also available with these types. Java programmers should be alert, when dealing with strings, to the fact that `==` compares by value in C# but by reference in Java when returning to their former language. +- Reference types (Instances of classes) are compared using the `Equals()` method inherited from `object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `object`'s implementation will suffice. If not, you need to override `object.Equals()`. +- If you know that all the instances of your class are created in one place, say characters in some game or simulation then reference equality is sufficient. However, it is likely that multiple instances of the same real-world entity will be created (for example, from a database, by user input, via a web request). In this case values that uniquely identify the entity must be tested for equality. Therefore `Equals()` must be overridden. +- An overridden `Equals()` will contain equality tests on members of simple types using `==` and reference types with recursive calls to `Equals()`. + +```csharp +class StatusBar +{ + private readonly int width = 200, height = 20; + + public override bool Equals(object other) + { + // ... null and type checks and performance optimisations + return width == (other as StatusBar).width && height == (other as StatusBar).height; + } +} +class Window +{ + private readonly string title = "Main"; + private readonly StatusBar statusBar = new StatusBar(); + + public override bool Equals(object other) + { + // ... null and type checks and performance optimisations + return title == (other as Window).title && statusBar.Equals((other as Window).statusBar); + } +} + +``` + +- The static method `object.ReferenceEquals()` is used to compare two objects to detect if they are one and the same instance. This provides clarity and is a necessity where `Equals()` and `==` have been overridden/overloaded. + +```csharp +var winA = new Window(); // above code shows that all windows are equal +var winB = new Window(); +ReferenceEquals(winA, winB); +// => false +var winC = winA; +ReferenceEquals(winA, winC); +// => true +``` + +#### Ancillary topics + +- In addition to `public override bool Equals(object obj)` IDEs typically generate the overload `protected bool Equals(FacialFeatures other)` for use when inheritance is involved. A derived class can call the base classe's `Equals()` and then add its own test. +- Do not use `==` unless you have [overloaded][operator-overloading] the `==` operator, as well as the `Equals()` method in your class (see the `operator-overloading` exercise) or you care only that the references are equal. +- Equality tests in [`struct`s][struct] are dealt with in the `structs` exercise. +- Equality of [`tuple`s][tuples-equality] is dealt with in the `tuples` exercise. +- Many developers rely on their IDEs to provide implementation of equality methods as these take care of all the minutiae of equality. For instance, JetBrains' RIDER (v 2020.1) generates the following equality methods for a class: + +```csharp +protected bool Equals(T other) +{ + return field1 == other.field1 && field2.Equals(other.field2); +} + +public override bool Equals(object obj) +{ + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((T) obj); +} +``` + +- Be careful if you decide to improve on the code generated by your IDE. That code is generally bullet-proof against nulls and mistyped objects and fairly well optimized. +- Tests for the equality of [delegates][delegate-equality] is not specifically discussed in the exercise. +- There are no built in equality tests for arrays nor most collections. [LINQ][linq] (discussed in later exercises) provides [`SequenceEquals()`][sequence-equal] but in the absence of LINQ it is a matter of iterating through both collections and comparing items individually. +- For a discussion of how to use `==` and `!=` with your own classes see the `operator-overloading` exercise. + +### `Object.GetHashCode()` + +- [`object.GetHashCode()`][get-hash-code] returns a hash code in the form of a 32 bit integer. The hash code is used by dictionary and set classes such as [`Dictionary`][dictionary] and [`HashSet`][hash-set] to store and retrieve objects in a performant manner. In the case of dictionaries the [hashing][wiki-hash] relates to the keys. +- There is an expectation amongst C# developers that if you override `Equals()` you will also override `GetHashCode()`. There is a relationship between `Equals()` and `GetHashCode()` that must hold true for correct behavior of dictionary and hash set classes and any others that use a hash code. You are expected to implement the method so that no traps are laid for maintainers who might add a hash code based collection at a later time. +- The relationship between hash code and equality is that if two objects are equal (`Equal()` returns true) then `GetHashCode()` for the two objects must return the same value. This does not apply in the reverse direction. It is not symmetrical. Picture a lookup function that first goes to a "bucket" based on the hash code and then picks out the particular item using the equality test. +- The easiest way to create a hashcode is to call [`HashCode.Combine()`][hash-code-combine] passing in the values used in the equality test (or a subset). Bear in mind the more information you provide to `Combine()` the more performant the hash implementation is likely to be. + +```csharp +public class Assessment +{ + private int rating; + private Person boss; + + public override int GetHashCode() + { + return HashCode.Combine(rating, boss); + } +} +``` + +- The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be [immutable][wiki-immutable]. Other approaches run the risk of creating gotchas for maintainers. Immutability is discussed in other exercises. +- It is possible that you can design a better hashcode than that produced by the library routines but either it's because you have a detailed understanding of the data's characteristics or because it is a very simple collection where values can be used directly without hashing. It may not be worth the extra effort. + +### Performance Enhancements + +To improve performance slightly, especially where objects belong to collections you can add an overloaded member `public bool Equals(T other)`. + +This will save a certain amount of type checking for reference types and will save a boxing step for value types as they will not need to be converted to an object (boxed) as an argument to `public override bool Equals(object other)`. + +If you add the interface `IEquatable` to your class this will require the overload to be implemented. Unless your code contains routines that take objects of type `IEquatable` (and presumably do something interesting relating to equality irrespective of the implementing class) there is really no other compelling to include the interface. + +### `IEqualityComparer` + +If you have a class that can be uniquely identified in two different ways, say a `Person` class that has a SSID and a unique email address then .NET provides a means to allow two different collections to use different hash-code and equality tests. Each can have an different implementation of `IEqualityComparer` with its own an `Equals()` and a `GetHashCode()` method. You can have a dictionary keyed on SSID and another keyed on email address. + +Where `IEqualityComparer` is in play you would typically still override `Equals()` and `GetHashCode()` on your item class to avoid problems outside the collection classes. + +One consideration when using `IEqualityComparer` is that private methods etc. will not be available for the equality test. + +If only one hashed collection is in play then it may be better to avoid `IEqualityComparer` and encapsulate equality and hash code in the object itself. It is not ideal, in the first place, that a key dependency such as that between object and hashed collection cannot be enforced by the compiler but with the hashing and comparison logic elsewhere it would be even easier for a maintainer to make changes to a class's members without regard to the consequences for the collection. + +### Note on floating-point equality + +One primitive that can challenge the unwary coder is testing the [equality of floating-point values][0.30000000000000004.com]. This is discussed in the _after.md_ document for the `floating-point-numbers` exercise. + +### Equality and Inheritance + +This [article][so-equals-inheritance] shows some of the decisions that have to be made with regard to equality and inheritance. They will only concern you if you are manipulating instances of a class and a derived class and need to test the equality between the two. + +[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons +[equatable]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type +[equality-comparer]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iequalitycomparer-1?view=netcore-3.1 +[hash-set]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 +[hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode?view=netcore-3.1 +[get-hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 +[delegate-equality]: https://docs.microsoft.com/en-us/dotnet/api/system.delegate.equals?view=netcore-3.1 +[sequence-equal]: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?redirectedfrom=MSDN&view=netcore-3.1#System_Linq_Enumerable_SequenceEqual__1_System_Collections_Generic_IEnumerable___0__System_Collections_Generic_IEnumerable___0__ +[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[so-equals-inheritance]: https://stackoverflow.com/questions/22154799/equals-method-inheritance-confusion +[object-equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ +[so-hashcode-equals]: https://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netcore-3.1 +[wiki-hash]: https://en.wikipedia.org/wiki/Hash_function +[hash-code-combine]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=netcore-3.1 +[wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object +[struct]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct +[tuples-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/tuple-equality diff --git a/concepts/equality/links.json b/concepts/equality/links.json index fe51488c70..4340b32b6b 100644 --- a/concepts/equality/links.json +++ b/concepts/equality/links.json @@ -1 +1,78 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_", + "description": "object-equals" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading", + "description": "operator-overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct", + "description": "struct" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/tuple-equality", + "description": "tuples-equality" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.delegate.equals?view=netcore-3.1", + "description": "delegate-equality" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/", + "description": "linq" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?redirectedfrom=MSDN\u0026view=netcore-3.1#System_Linq_Enumerable_SequenceEqual__1_System_Collections_Generic_IEnumerable___0__System_Collections_Generic_IEnumerable___0__", + "description": "sequence-equal" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1", + "description": "get-hash-code" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netcore-3.1", + "description": "dictionary" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1", + "description": "hash-set" + }, + { + "url": "https://en.wikipedia.org/wiki/Hash_function", + "description": "wiki-hash" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=netcore-3.1", + "description": "hash-code-combine" + }, + { + "url": "https://en.wikipedia.org/wiki/Immutable_object", + "description": "wiki-immutable" + }, + { + "url": "https://0.30000000000000004.com/", + "description": "0.30000000000000004.com" + }, + { + "url": "https://stackoverflow.com/questions/22154799/equals-method-inheritance-confusion", + "description": "so-equals-inheritance" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons", + "description": "equality" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.hashcode?view=netcore-3.1", + "description": "hash-code" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1", + "description": "get-hash-code" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1", + "description": "hash-set" + } +] diff --git a/exercises/concept/equality/.docs/after.md b/exercises/concept/equality/.docs/after.md deleted file mode 100644 index c6a6b7ee06..0000000000 --- a/exercises/concept/equality/.docs/after.md +++ /dev/null @@ -1,152 +0,0 @@ -The coding exercise illustrates a number of properties of equality in C#: - -### `Object.Equals()` - -#### Topics covered by the coding exercise - -- Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. This is considered more idiomatic than using the [`Equals()`][object-equals] method which is also available with these types. Java programmers should be alert, when dealing with strings, to the fact that `==` compares by value in C# but by reference in Java when returning to their former language. -- Reference types (Instances of classes) are compared using the `Equals()` method inherited from `object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `object`'s implementation will suffice. If not, you need to override `object.Equals()`. -- If you know that all the instances of your class are created in one place, say characters in some game or simulation then reference equality is sufficient. However, it is likely that multiple instances of the same real-world entity will be created (for example, from a database, by user input, via a web request). In this case values that uniquely identify the entity must be tested for equality. Therefore `Equals()` must be overridden. -- An overridden `Equals()` will contain equality tests on members of simple types using `==` and reference types with recursive calls to `Equals()`. - -```csharp -class StatusBar -{ - private readonly int width = 200, height = 20; - - public override bool Equals(object other) - { - // ... null and type checks and performance optimisations - return width == (other as StatusBar).width && height == (other as StatusBar).height; - } -} -class Window -{ - private readonly string title = "Main"; - private readonly StatusBar statusBar = new StatusBar(); - - public override bool Equals(object other) - { - // ... null and type checks and performance optimisations - return title == (other as Window).title && statusBar.Equals((other as Window).statusBar); - } -} - -``` - -- The static method `object.ReferenceEquals()` is used to compare two objects to detect if they are one and the same instance. This provides clarity and is a necessity where `Equals()` and `==` have been overridden/overloaded. - -```csharp -var winA = new Window(); // above code shows that all windows are equal -var winB = new Window(); -ReferenceEquals(winA, winB); -// => false -var winC = winA; -ReferenceEquals(winA, winC); -// => true -``` - -#### Ancillary topics - -- In addition to `public override bool Equals(object obj)` IDEs typically generate the overload `protected bool Equals(FacialFeatures other)` for use when inheritance is involved. A derived class can call the base classe's `Equals()` and then add its own test. -- Do not use `==` unless you have [overloaded][operator-overloading] the `==` operator, as well as the `Equals()` method in your class (see the `operator-overloading` exercise) or you care only that the references are equal. -- Equality tests in [`struct`s][struct] are dealt with in the `structs` exercise. -- Equality of [`tuple`s][tuples-equality] is dealt with in the `tuples` exercise. -- Many developers rely on their IDEs to provide implementation of equality methods as these take care of all the minutiae of equality. For instance, JetBrains' RIDER (v 2020.1) generates the following equality methods for a class: - -```csharp -protected bool Equals(T other) -{ - return field1 == other.field1 && field2.Equals(other.field2); -} - -public override bool Equals(object obj) -{ - if (ReferenceEquals(null, obj)) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; - return Equals((T) obj); -} -``` - -- Be careful if you decide to improve on the code generated by your IDE. That code is generally bullet-proof against nulls and mistyped objects and fairly well optimized. -- Tests for the equality of [delegates][delegate-equality] is not specifically discussed in the exercise. -- There are no built in equality tests for arrays nor most collections. [LINQ][linq] (discussed in later exercises) provides [`SequenceEquals()`][sequence-equal] but in the absence of LINQ it is a matter of iterating through both collections and comparing items individually. -- For a discussion of how to use `==` and `!=` with your own classes see the `operator-overloading` exercise. - -### `Object.GetHashCode()` - -- [`object.GetHashCode()`][get-hash-code] returns a hash code in the form of a 32 bit integer. The hash code is used by dictionary and set classes such as [`Dictionary`][dictionary] and [`HashSet`][hash-set] to store and retrieve objects in a performant manner. In the case of dictionaries the [hashing][wiki-hash] relates to the keys. -- There is an expectation amongst C# developers that if you override `Equals()` you will also override `GetHashCode()`. There is a relationship between `Equals()` and `GetHashCode()` that must hold true for correct behavior of dictionary and hash set classes and any others that use a hash code. You are expected to implement the method so that no traps are laid for maintainers who might add a hash code based collection at a later time. -- The relationship between hash code and equality is that if two objects are equal (`Equal()` returns true) then `GetHashCode()` for the two objects must return the same value. This does not apply in the reverse direction. It is not symmetrical. Picture a lookup function that first goes to a "bucket" based on the hash code and then picks out the particular item using the equality test. -- The easiest way to create a hashcode is to call [`HashCode.Combine()`][hash-code-combine] passing in the values used in the equality test (or a subset). Bear in mind the more information you provide to `Combine()` the more performant the hash implementation is likely to be. - -```csharp -public class Assessment -{ - private int rating; - private Person boss; - - public override int GetHashCode() - { - return HashCode.Combine(rating, boss); - } -} -``` - -- The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be [immutable][wiki-immutable]. Other approaches run the risk of creating gotchas for maintainers. Immutability is discussed in other exercises. -- It is possible that you can design a better hashcode than that produced by the library routines but either it's because you have a detailed understanding of the data's characteristics or because it is a very simple collection where values can be used directly without hashing. It may not be worth the extra effort. - -### Performance Enhancements - -To improve performance slightly, especially where objects belong to collections you can add an overloaded member `public bool Equals(T other)`. - -This will save a certain amount of type checking for reference types and will save a boxing step for value types as they will not need to be converted to an object (boxed) as an argument to `public override bool Equals(object other)`. - -If you add the interface `IEquatable` to your class this will require the overload to be implemented. Unless your code contains routines that take objects of type `IEquatable` (and presumably do something interesting relating to equality irrespective of the implementing class) there is really no other compelling to include the interface. - -### `IEqualityComparer` - -If you have a class that can be uniquely identified in two different ways, say a `Person` class that has a SSID and a unique email address then .NET provides a means to allow two different collections to use different hash-code and equality tests. Each can have an different implementation of `IEqualityComparer` with its own an `Equals()` and a `GetHashCode()` method. You can have a dictionary keyed on SSID and another keyed on email address. - -Where `IEqualityComparer` is in play you would typically still override `Equals()` and `GetHashCode()` on your item class to avoid problems outside the collection classes. - -One consideration when using `IEqualityComparer` is that private methods etc. will not be available for the equality test. - -If only one hashed collection is in play then it may be better to avoid `IEqualityComparer` and encapsulate equality and hash code in the object itself. It is not ideal, in the first place, that a key dependency such as that between object and hashed collection cannot be enforced by the compiler but with the hashing and comparison logic elsewhere it would be even easier for a maintainer to make changes to a class's members without regard to the consequences for the collection. - -### Note on floating-point equality - -One primitive that can challenge the unwary coder is testing the [equality of floating-point values][0.30000000000000004.com]. This is discussed in the _after.md_ document for the `floating-point-numbers` exercise. - -### Equality and Inheritance - -This [article][so-equals-inheritance] shows some of the decisions that have to be made with regard to equality and inheritance. They will only concern you if you are manipulating instances of a class and a derived class and need to test the equality between the two. - -### General Informaton - -- [Equality][equality]: how equality comparisons work in C#, including reference- and value type equality. -- [HashCode][hash-code]: how to create and combine hash codes -- [GetHashCode][get-hash-code]: API documentation -- [HashSet][hash-set]: API documentation - -[equality]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons -[equatable]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/how-to-define-value-equality-for-a-type -[equality-comparer]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.iequalitycomparer-1?view=netcore-3.1 -[hash-set]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.hashset-1?view=netcore-3.1 -[hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode?view=netcore-3.1 -[get-hash-code]: https://docs.microsoft.com/en-us/dotnet/api/system.object.gethashcode?view=netcore-3.1 -[delegate-equality]: https://docs.microsoft.com/en-us/dotnet/api/system.delegate.equals?view=netcore-3.1 -[sequence-equal]: https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.sequenceequal?redirectedfrom=MSDN&view=netcore-3.1#System_Linq_Enumerable_SequenceEqual__1_System_Collections_Generic_IEnumerable___0__System_Collections_Generic_IEnumerable___0__ -[linq]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/ -[0.30000000000000004.com]: https://0.30000000000000004.com/ -[so-equals-inheritance]: https://stackoverflow.com/questions/22154799/equals-method-inheritance-confusion -[object-equals]: https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-3.1#System_Object_Equals_System_Object_ -[so-hashcode-equals]: https://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden -[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading -[dictionary]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.generic.dictionary-2?view=netcore-3.1 -[wiki-hash]: https://en.wikipedia.org/wiki/Hash_function -[hash-code-combine]: https://docs.microsoft.com/en-us/dotnet/api/system.hashcode.combine?view=netcore-3.1 -[wiki-immutable]: https://en.wikipedia.org/wiki/Immutable_object -[struct]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/struct -[tuples-equality]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-7.3/tuple-equality From d9c5914aa3b7db4d0d5996b7984f5da2f56a9bfe Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 15:55:19 +0200 Subject: [PATCH 244/327] enums - replace about.md file with concept files * Pre-populate enums concept's about.md file from after.md file * Pre-populate pattern-matching-constants concept's about.md file from after.md file * enums - Remove after.md document * Update about.md Co-authored-by: Mike May --- concepts/enums/about.md | 39 +++++++++++++++++++++++++- exercises/concept/enums/.docs/after.md | 38 ------------------------- 2 files changed, 38 insertions(+), 39 deletions(-) delete mode 100644 exercises/concept/enums/.docs/after.md diff --git a/concepts/enums/about.md b/concepts/enums/about.md index d497cddaa5..fa2e10dc8a 100644 --- a/concepts/enums/about.md +++ b/concepts/enums/about.md @@ -1 +1,38 @@ -TODO: add information on enums concept +You can use an enum whenever you have a fixed set of constant values. Using an enum gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`). + +Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`. + +```csharp +enum Season +{ + Spring, // Value is 0 + Summer = 2, // Value is 2 + Autumn, // Value is 3 + Winter = 7 // Value is 7 +} +``` + +Enums are very declarative. Compare the following two method calls: + +```csharp +Users.WithStatus(1) +Users.WithStatus(Status.Active) +``` + +For someone reading the code, the second (enum) version will be easier to comprehend. + +You should always consider using an enum whenever you want to model something as a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof. + +Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to any enum value: + +```csharp +enum Status +{ + Inactive = 0, + Active = 1 +} + +Status status = (Status) 2; +status == Status.Inactive; // False +status == Status.Active; // False +``` diff --git a/exercises/concept/enums/.docs/after.md b/exercises/concept/enums/.docs/after.md deleted file mode 100644 index fa2e10dc8a..0000000000 --- a/exercises/concept/enums/.docs/after.md +++ /dev/null @@ -1,38 +0,0 @@ -You can use an enum whenever you have a fixed set of constant values. Using an enum gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`). - -Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`. - -```csharp -enum Season -{ - Spring, // Value is 0 - Summer = 2, // Value is 2 - Autumn, // Value is 3 - Winter = 7 // Value is 7 -} -``` - -Enums are very declarative. Compare the following two method calls: - -```csharp -Users.WithStatus(1) -Users.WithStatus(Status.Active) -``` - -For someone reading the code, the second (enum) version will be easier to comprehend. - -You should always consider using an enum whenever you want to model something as a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof. - -Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to any enum value: - -```csharp -enum Status -{ - Inactive = 0, - Active = 1 -} - -Status status = (Status) 2; -status == Status.Inactive; // False -status == Status.Active; // False -``` From 82b6766e0ef159de9ac7ea43b81de41fa8ef2013 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:01:25 +0200 Subject: [PATCH 245/327] booleans - replace about.md file with concept files * Pre-populate booleans concept's about.md file from after.md file * Pre-populate booleans concept's links.json file from after.md file * booleans - Remove after.md document --- concepts/booleans/about.md | 19 ++++++++++++++++++- concepts/booleans/links.json | 11 ++++++++++- exercises/concept/booleans/.docs/after.md | 18 ------------------ 3 files changed, 28 insertions(+), 20 deletions(-) delete mode 100644 exercises/concept/booleans/.docs/after.md diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md index d461152b95..368f4d97db 100644 --- a/concepts/booleans/about.md +++ b/concepts/booleans/about.md @@ -1 +1,18 @@ -TODO: add information on booleans concept +Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`. + +C# supports three [boolean operators][operators]: `!` (NOT), `&&` (AND), and `||` (OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. + +```csharp +true || false // => true +true && false // => false +``` + +The three boolean operators each have a different [_operator precedence_][precedence]. As a consequence, they are evaluated in this order: `not` first, `&&` second, and finally `||`. If you want to 'escape' these rules, you can enclose a boolean expression in parentheses (`()`), as the parentheses have an even higher operator precedence. + +```csharp +!true && false // => false +!(true && false) // => true +``` + +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators +[precedence]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#operator-precedence diff --git a/concepts/booleans/links.json b/concepts/booleans/links.json index fe51488c70..ff67be132f 100644 --- a/concepts/booleans/links.json +++ b/concepts/booleans/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators", + "description": "operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#operator-precedence", + "description": "precedence" + } +] diff --git a/exercises/concept/booleans/.docs/after.md b/exercises/concept/booleans/.docs/after.md deleted file mode 100644 index 368f4d97db..0000000000 --- a/exercises/concept/booleans/.docs/after.md +++ /dev/null @@ -1,18 +0,0 @@ -Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`. - -C# supports three [boolean operators][operators]: `!` (NOT), `&&` (AND), and `||` (OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed. - -```csharp -true || false // => true -true && false // => false -``` - -The three boolean operators each have a different [_operator precedence_][precedence]. As a consequence, they are evaluated in this order: `not` first, `&&` second, and finally `||`. If you want to 'escape' these rules, you can enclose a boolean expression in parentheses (`()`), as the parentheses have an even higher operator precedence. - -```csharp -!true && false // => false -!(true && false) // => true -``` - -[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators -[precedence]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/boolean-logical-operators#operator-precedence From 32444fd51701a1762ff81d5c7fa348c7fd20a5a9 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:02:21 +0200 Subject: [PATCH 246/327] basics - replace about.md file with concept files * Pre-populate basics concept's about.md file from after.md file * Pre-populate basics concept's links.json file from after.md file * basics - Remove after.md document --- concepts/basics/about.md | 80 ++++++++++++++++++++++++- concepts/basics/links.json | 31 +++++++++- exercises/concept/basics/.docs/after.md | 79 ------------------------ 3 files changed, 109 insertions(+), 81 deletions(-) delete mode 100644 exercises/concept/basics/.docs/after.md diff --git a/concepts/basics/about.md b/concepts/basics/about.md index 246577017b..343febaddd 100644 --- a/concepts/basics/about.md +++ b/concepts/basics/about.md @@ -1 +1,79 @@ -TODO: add information on basics concept +C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value. + +```csharp +int explicitVar = 10; // Explicitly typed +var implicitVar = 10; // Implicitly typed +``` + +The value of a variable can be assigned and updated using the [`=` operator][assignment]. Once defined, a variable's type can never change. + +```csharp +var count = 1; // Assign initial value +count = 2; // Update to new value + +// Compiler error when assigning different type +// count = false; +``` + +C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. Objects (or _instances_) are created by using the `new` keyword. + +```csharp +class Calculator +{ + // ... +} + +var calculator = new Calculator(); +``` + +A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from methods using the [`return` keyword][return]. To allow a method to be called by code in other files, the `public` access modifier must be added. + +```csharp +class Calculator +{ + public int Add(int x, int y) + { + return x + y; + } +} +``` + +Methods are invoked using dot (`.`) syntax on an instance, specifying the method name to call and passing arguments for each of the method's parameters. Arguments can optionally specify the corresponding parameter's name. + +```csharp +var calculator = new Calculator(); +var sum_v1 = calculator.Add(1, 2); +var sum_v2 = calculator.Add(x: 1, y: 2); +``` + +If the method to be called is defined in the same class as the method that calls it, the class name can be omitted. + +If a method does not use any object _state_, the method can be made _static_ using the `static` modifier. Static methods are also invoked using dot (`.`) syntax, but are invoked on the class itself instead of an instance of the class. + +If a class only has static methods, it too can be made static using the `static` modifier. This expresses the intention of the class. + +```csharp +static class Calculator +{ + public static int Multiply(int x, int y) + { + return x * y; + } +} + +Calculator.Multiply(2, 4); // => 8 +``` + +Scope in C# is defined between the `{` and `}` characters. + +C# supports two types of [comments][comments]. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. + +Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators]. + +[assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator +[var]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var +[classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#declaring-classes +[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/methods +[return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return +[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator- +[comments]: https://www.w3schools.com/cs/cs_comments.asp diff --git a/concepts/basics/links.json b/concepts/basics/links.json index fe51488c70..b26b0bf896 100644 --- a/concepts/basics/links.json +++ b/concepts/basics/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var", + "description": "var" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator", + "description": "assignment" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#declaring-classes", + "description": "classes" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/methods", + "description": "methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return", + "description": "return" + }, + { + "url": "https://www.w3schools.com/cs/cs_comments.asp", + "description": "comments" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator-", + "description": "operators" + } +] diff --git a/exercises/concept/basics/.docs/after.md b/exercises/concept/basics/.docs/after.md deleted file mode 100644 index 343febaddd..0000000000 --- a/exercises/concept/basics/.docs/after.md +++ /dev/null @@ -1,79 +0,0 @@ -C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value. - -```csharp -int explicitVar = 10; // Explicitly typed -var implicitVar = 10; // Implicitly typed -``` - -The value of a variable can be assigned and updated using the [`=` operator][assignment]. Once defined, a variable's type can never change. - -```csharp -var count = 1; // Assign initial value -count = 2; // Update to new value - -// Compiler error when assigning different type -// count = false; -``` - -C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. Objects (or _instances_) are created by using the `new` keyword. - -```csharp -class Calculator -{ - // ... -} - -var calculator = new Calculator(); -``` - -A function within a class is referred to as a _method_. Each [method][methods] can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from methods using the [`return` keyword][return]. To allow a method to be called by code in other files, the `public` access modifier must be added. - -```csharp -class Calculator -{ - public int Add(int x, int y) - { - return x + y; - } -} -``` - -Methods are invoked using dot (`.`) syntax on an instance, specifying the method name to call and passing arguments for each of the method's parameters. Arguments can optionally specify the corresponding parameter's name. - -```csharp -var calculator = new Calculator(); -var sum_v1 = calculator.Add(1, 2); -var sum_v2 = calculator.Add(x: 1, y: 2); -``` - -If the method to be called is defined in the same class as the method that calls it, the class name can be omitted. - -If a method does not use any object _state_, the method can be made _static_ using the `static` modifier. Static methods are also invoked using dot (`.`) syntax, but are invoked on the class itself instead of an instance of the class. - -If a class only has static methods, it too can be made static using the `static` modifier. This expresses the intention of the class. - -```csharp -static class Calculator -{ - public static int Multiply(int x, int y) - { - return x * y; - } -} - -Calculator.Multiply(2, 4); // => 8 -``` - -Scope in C# is defined between the `{` and `}` characters. - -C# supports two types of [comments][comments]. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`. - -Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators]. - -[assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator -[var]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var -[classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#declaring-classes -[methods]: https://docs.microsoft.com/en-us/dotnet/csharp/methods -[return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return -[operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator- -[comments]: https://www.w3schools.com/cs/cs_comments.asp From 790593eb9765c038def147fa56a7c61004ab9101 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:05:42 +0200 Subject: [PATCH 247/327] constants - replace about.md file with concept files * Pre-populate constants concept's about.md file from after.md file * Pre-populate constants concept's links.json file from after.md file * Pre-populate defensive-copying concept's about.md file from after.md file * Pre-populate defensive-copying concept's links.json file from after.md file * Pre-populate readonly-collections concept's about.md file from after.md file * Pre-populate readonly-collections concept's links.json file from after.md file * constants - Remove after.md document * Update about.md * Update links.json * Update about.md * Update links.json * Update about.md * Update links.json Co-authored-by: Mike May --- concepts/constants/about.md | 69 +++++++++++++++++- concepts/constants/links.json | 35 ++++++++- concepts/defensive-copying/about.md | 7 +- concepts/defensive-copying/links.json | 11 ++- concepts/readonly-collections/links.json | 7 +- exercises/concept/constants/.docs/after.md | 82 ---------------------- 6 files changed, 124 insertions(+), 87 deletions(-) delete mode 100644 exercises/concept/constants/.docs/after.md diff --git a/concepts/constants/about.md b/concepts/constants/about.md index e0a19de3d8..bf8ef965da 100644 --- a/concepts/constants/about.md +++ b/concepts/constants/about.md @@ -1 +1,68 @@ -TODO: add information on constants concept +#### const + +The [`const`][constants] modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program. + +```csharp +private const int num = 1729; +public const string title = "Grand" + " Master"; +``` + +The compiler will guide you as to what expressions can be evaluated at compile-time. Simple arithmetic operations are allowed as is string concatenation. This excludes any evaluation that would require use of the heap or stack so all method calls and references to non-primitive types are not available. + +There is some discussion on the web about the performance advantages of `const` over variables. In the case of a comparison with instance non-const fields there could be a noticeable saving in memory but compared to static variables that is decidedly trivial. Any consideration of CPU performance is likely to be seen by your colleagues as [premature optimization][premature-optimization]. + +A more compelling reason to use `const` is that it enhances a maintainer's ability to reason about the code. Glimpsing that a field is marked as `const` or `readonly` or that a property has no setter allows the maintainer largely to dismiss it from their analysis. It is unlikely to be the seat of bugs. It is unlikely to pose difficulties in a refactoring exercise. This [Stack Overflow comment][so-consts] addresses this. + +The `const` modifier can also be applied to values within methods: + +```csharp +public double Area(double r) +{ + const double π = 3.142; + return System.Math.Pow((π * r), 2); +} +``` + +Identifying a value with `const` in this way can be useful if it is used multiple times in the method or you want to draw attention to its meaning. There is no performance gain over using literals inline. + +#### readonly + +The [`readonly`][readonly-fields] modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor). + +```csharp +private readonly int num; +private readonly System.Random rand = new System.Random(); + +public MyClass(int num) +{ + this.num = num; +} +``` + +Use of the `readonly` modifier is encouraged for the same reasons that apply to `const`. The practice of constraining fields in this way helps maintainers reason about the code. + +Note that adding the `readonly` modifier to a field prevents only the value of the field from being changed. In the case of aggregate types it does not protect the fields or properties of that type. In particular, it does not protect the contents of arrays. + +```csharp +private readonly IList list = new List(); + +public void Foo() +{ + list = new List(); // does not compile + + list.Add("new stuff"); // succeeds at runtime +} +``` + +To ensure that all members of a reference type are protected the fields can be made `readonly` and automatic properties can be defined without a `set` accessor. + +You should examine [read-only collections][readonly-collections] in the Base Class Library. + +For arrays the closest you can get to a read-only version is the [`Array.AsReadOnly()][as-read-only] method. + +[readonly-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example +[constants]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants +[so-consts]: https://stackoverflow.com/a/5834473/96167 +[premature-optimization]: https://wiki.c2.com/?PrematureOptimization +[as-read-only]: https://docs.microsoft.com/en-us/dotnet/api/system.array.asreadonly?view=netcore-3.1 +[readonly-collections]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1?view=netcore-3.1 diff --git a/concepts/constants/links.json b/concepts/constants/links.json index fe51488c70..ee44a00ce1 100644 --- a/concepts/constants/links.json +++ b/concepts/constants/links.json @@ -1 +1,34 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants", + "description": "constants" + }, + { + "url": "https://wiki.c2.com/?PrematureOptimization", + "description": "premature-optimization" + }, + { + "url": "https://stackoverflow.com/a/5834473/96167", + "description": "so-consts" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example", + "description": "readonly-fields" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1?view=netcore-3.1", + "description": "readonly-collections" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array.asreadonly?view=netcore-3.1", + "description": "as-read-only" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example", + "description": "readonly-fields" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants", + "description": "constants" + } +] diff --git a/concepts/defensive-copying/about.md b/concepts/defensive-copying/about.md index 0a810479c5..58d920b686 100644 --- a/concepts/defensive-copying/about.md +++ b/concepts/defensive-copying/about.md @@ -1 +1,6 @@ -TODO: add information on defensive-copying concept +Imagine you have a code-base of several hundred thousand lines. You are passed the dictionary of developers into some method you are developing. Perhaps you have been tasked with printing out details of privileged developers. You decide to blank out the eye color in the dictionary to protect the developers' privacy. Unless a [deep copy][so-deep-copy] of the dictionary was made in the `Authenticator.GetDevelopers()` method, or, even better, it was wrapped in a read-only collection then you will have just trashed the authenticator. + +This follows the principle of [defensive copying][defensive-copying]. You can make sure your formal API is not circumvented by avoiding exposure to callers of internal writeable state. + +[so-deep-copy]: https://stackoverflow.com/questions/78536/deep-cloning-objects +[defensive-copying]: https://www.informit.com/articles/article.aspx?p=31551&seqNum=2 diff --git a/concepts/defensive-copying/links.json b/concepts/defensive-copying/links.json index fe51488c70..c1fee10a0a 100644 --- a/concepts/defensive-copying/links.json +++ b/concepts/defensive-copying/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://stackoverflow.com/questions/78536/deep-cloning-objects", + "description": "so-deep-copy" + }, + { + "url": "https://www.informit.com/articles/article.aspx?p=31551\u0026seqNum=2", + "description": "defensive-copying" + } +] diff --git a/concepts/readonly-collections/links.json b/concepts/readonly-collections/links.json index fe51488c70..8f2b5ce50b 100644 --- a/concepts/readonly-collections/links.json +++ b/concepts/readonly-collections/links.json @@ -1 +1,6 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1?view=netcore-3.1", + "description": "readonly-collections" + } +] diff --git a/exercises/concept/constants/.docs/after.md b/exercises/concept/constants/.docs/after.md deleted file mode 100644 index d1aec92b5a..0000000000 --- a/exercises/concept/constants/.docs/after.md +++ /dev/null @@ -1,82 +0,0 @@ -#### const - -The [`const`][constants] modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program. - -```csharp -private const int num = 1729; -public const string title = "Grand" + " Master"; -``` - -The compiler will guide you as to what expressions can be evaluated at compile-time. Simple arithmetic operations are allowed as is string concatenation. This excludes any evaluation that would require use of the heap or stack so all method calls and references to non-primitive types are not available. - -There is some discussion on the web about the performance advantages of `const` over variables. In the case of a comparison with instance non-const fields there could be a noticeable saving in memory but compared to static variables that is decidedly trivial. Any consideration of CPU performance is likely to be seen by your colleagues as [premature optimization][premature-optimization]. - -A more compelling reason to use `const` is that it enhances a maintainer's ability to reason about the code. Glimpsing that a field is marked as `const` or `readonly` or that a property has no setter allows the maintainer largely to dismiss it from their analysis. It is unlikely to be the seat of bugs. It is unlikely to pose difficulties in a refactoring exercise. This [Stack Overflow comment][so-consts] addresses this. - -The `const` modifier can also be applied to values within methods: - -```csharp -public double Area(double r) -{ - const double π = 3.142; - return System.Math.Pow((π * r), 2); -} -``` - -Identifying a value with `const` in this way can be useful if it is used multiple times in the method or you want to draw attention to its meaning. There is no performance gain over using literals inline. - -#### readonly - -The [`readonly`][readonly-fields] modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor). - -```csharp -private readonly int num; -private readonly System.Random rand = new System.Random(); - -public MyClass(int num) -{ - this.num = num; -} -``` - -Use of the `readonly` modifier is encouraged for the same reasons that apply to `const`. The practice of constraining fields in this way helps maintainers reason about the code. - -Note that adding the `readonly` modifier to a field prevents only the value of the field from being changed. In the case of aggregate types it does not protect the fields or properties of that type. In particular, it does not protect the contents of arrays. - -```csharp -private readonly IList list = new List(); - -public void Foo() -{ - list = new List(); // does not compile - - list.Add("new stuff"); // succeeds at runtime -} -``` - -To ensure that all members of a reference type are protected the fields can be made `readonly` and automatic properties can be defined without a `set` accessor. - -You should examine [read-only collections][readonly-collections] in the Base Class Library. - -For arrays the closest you can get to a read-only version is the [`Array.AsReadOnly()][as-read-only] method. - -#### Defensive Copying - -Reflecting back on the coding exercise, imagine you have a code-base of several hundred thousand lines. You are passed the dictionary of developers into some method you are developing. Perhaps you have been tasked with printing out details of privileged developers. You decide to blank out the eye color in the dictionary to protect the developers' privacy. Unless a [deep copy][so-deep-copy] of the dictionary was made in the `Authenticator.GetDevelopers()` method, or, even better, it was wrapped in a read-only collection then you will have just trashed the authenticator. - -This follows the principle of [defensive copying][defensive-copying]. You can make sure your formal API is not circumvented by avoiding exposure to callers of internal writeable state. - -#### Reference - -- [Readonly fields][readonly-fields]: how to define a readonly field. -- [Constants][constants]: how to define constants. - -[readonly-fields]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/readonly#readonly-field-example -[constants]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/constants -[so-consts]: https://stackoverflow.com/a/5834473/96167 -[premature-optimization]: https://wiki.c2.com/?PrematureOptimization -[so-deep-copy]: https://stackoverflow.com/questions/78536/deep-cloning-objects -[defensive-copying]: https://www.informit.com/articles/article.aspx?p=31551&seqNum=2 -[as-read-only]: https://docs.microsoft.com/en-us/dotnet/api/system.array.asreadonly?view=netcore-3.1 -[readonly-collections]: https://docs.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1?view=netcore-3.1 -[so-deep-copy]: https://stackoverflow.com/questions/184710/what-is-the-difference-between-a-deep-copy-and-a-shallow-copy#:~:text=A%20deep%20copy%20occurs%20when,objects%20to%20which%20it%20refers.&text=Shallow%20copy%20is%20a%20bit,values%20in%20the%20original%20object. From 9c8ef9d858638811413687a4cdd4a669e107a91b Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:12:50 +0200 Subject: [PATCH 248/327] casting - replace about.md file with concept files * Pre-populate casting concept's about.md file from after.md file * Pre-populate casting concept's links.json file from after.md file * casting - Remove after.md document * Update about.md Co-authored-by: Mike May --- concepts/casting/about.md | 147 ++++++++++++++++++++- concepts/casting/links.json | 87 ++++++++++++- exercises/concept/casting/.docs/after.md | 155 ----------------------- 3 files changed, 232 insertions(+), 157 deletions(-) delete mode 100644 exercises/concept/casting/.docs/after.md diff --git a/concepts/casting/about.md b/concepts/casting/about.md index 0667536eb3..96fffe3d56 100644 --- a/concepts/casting/about.md +++ b/concepts/casting/about.md @@ -1 +1,146 @@ -TODO: add information on casting concept +Casting and type conversion [are different ways of changing an expression from one data type to another][wiki-casting]. + +The [C# documentation][type-testing-and-cast-operators] classifies type conversion as the use of the [`as` operator][as-operator] or [`is` operator][is-operator]. Casting is defined as the use of the [cast operator][cast-operator]. + +In C# very often, outside of the realm of numeric values and class hierarchies, you will have to make a conversion by calling some member of the "to" type such as [`Int32.Parse()`][int32-parse] which converts a string to an integer or by calling a member of the "from" type e.g. `object.ToString()`. Javascript and developers in other dynamic languages should be aware. + +Note that implicit an explicit cast [operators][operator-overloading] (discussed in (TODO cross-ref-tba)) are available which can bring fairly arbitrary casting to your own types. + +#### Casting Primitive Types - Implicit + +C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. Note in the documentation the exception for converting to real numbers where precision may be lost. + +An implicit cast is not signified by any special syntax. For example: + +```csharp +int myInt = 1729; +long myLong = myInt; +``` + +There is no implicit conversion of a numeric (or string) expression to `bool`. The Base Class Library (BCL) provides `Convert.ToBoolean()` for this purpose. + +An expression of type `char` can be implicitly cast to `int`. The cast in the opposite direction must be explicit. Not all values of `int` are valid utf 16 chars. + +#### Casting Primitive Types - Explicit + +Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. + +Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown in the case of integers, or the "to" type variable may take a value of `Infinity` in the case of floats and doubles. + +An expression of type `int` can be explicitly cast to `char`. This may result in an invalid `char`. + +#### Casting Primitive Types - Examples + +```csharp +int largeInt = Int32.MaxValue; +int largeNegInt = Int32.MinValue; +ushort shortUnsignedInt = ushort.MaxValue; +float largeFloat = float.MaxValue; +float smallFloat = 17.29f; + +// implicit cast +int from_ushort = shortUnsignedInt; // 65535 +float from_int = largeInt; // -21474836E+09 +int from_char = 'a'; // 96 + +// explicit cast +uint from_largeInt = (uint)largeInt; // 2147483647 +uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) +int from_smallFloat = (int) smallFloat; // 17 +int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked) +char from_intc = (char) 32; // ' ' +char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown + +// no cast available +int fromString = Int32.Parse("42"); // 42 +string toString = largeInt.ToString(); // "2147483647" +int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown +``` + +See this [article][checked] for the _**checked**_ keyword. + +#### Type Conversion for types in a hierarchy + +Any type can be implicitly converted to its base class or interface. + +```csharp +IList ll = new List(); +``` + +A cast operator can be used to convert from a base to a derived class. + +```csharp +IList ll = new List(); +List l = (List)ll; +``` + +If the cast fails because the type of the expression being cast is not related to the type it is being cast to an instance of `InvalidCastException` is thrown. + +A more usual approach to these type conversions is to use the [`is`][is-operator] keyword: + +```csharp +interface IFoo { int Bar(); } +class Foo : IFoo { public int Bar() { return 42; }} +Object r = new Random(); +IFoo ifoo = new Foo(); +Object o = new Foo(); + +int result = 1729; + +if (ifoo is Foo foo) +{ + result = foo.Bar(); +} +// result == 42 + +result = 1729; +if (o is Foo foo2) +{ + result = foo2.Bar(); +} +// result == 42 + +result = 1729; +if (r is Foo foo3) +{ + result = foo3.Bar(); +} +// result == 1729 +``` + +The [`as`][as-operator] keyword fulfills a similar function to `is` e.g. `var foo = ifoo as Foo;`. In this example `foo` will be `null` if `ifoo` is not of type `Foo` otherwise `ifoo` will be assigned to it. + +#### Custom Cast Operator + +Types can define their own custom explicit and implicit [cast operators][custom-casts]. See (TODO cross-ref-tba) for coverage of this.. + +Examples of [explicit][big-integer-explicit] and [implicit][big-integer-implicit] casts in the BCL is conversions from the `BigInteger` struct to and from other numeric types + +#### Using `typeof` + +If you need to detect the precise type of an object then `is` may be a little too permissive as it will convert an object to a class or any of its base classes. `typeof` and `Object.GetType()` are the solution in this case. + +```csharp +object o = new List(); + +o is ICollection // true +o.GetType() == typeof(ICollection) // false +o is List // true +o.GetType() == typeof(List) // true +``` + +[type-testing-and-cast-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast +[is-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator +[as-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator +[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression +[typeof-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator +[type-conversion-exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#type-conversion-exceptions-at-run-time +[wiki-casting]: https://en.wikipedia.org/wiki/Type_conversion +[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions +[explicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions +[int32-parse]: https://docs.microsoft.com/en-us/dotnet/api/system.int32.parse?view=netcore-3.1 +[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading +[checked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked +[custom-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators +[big-integer-implicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_implicit?view=netcore-3.1 +[big-integer-explicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_explicit?view=netcore-3.1 diff --git a/concepts/casting/links.json b/concepts/casting/links.json index fe51488c70..c51bafccf7 100644 --- a/concepts/casting/links.json +++ b/concepts/casting/links.json @@ -1 +1,86 @@ -[] +[ + { + "url": "https://en.wikipedia.org/wiki/Type_conversion", + "description": "wiki-casting" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast", + "description": "type-testing-and-cast-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator", + "description": "as-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator", + "description": "is-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression", + "description": "cast-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.int32.parse?view=netcore-3.1", + "description": "int32-parse" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading", + "description": "operator-overloading" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions", + "description": "implicit-casts" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression", + "description": "cast-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked", + "description": "checked" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator", + "description": "is-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator", + "description": "as-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators", + "description": "custom-casts" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_explicit?view=netcore-3.1", + "description": "big-integer-explicit" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_implicit?view=netcore-3.1", + "description": "big-integer-implicit" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast", + "description": "type-testing-and-cast-operators" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression", + "description": "cast-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator", + "description": "is-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator", + "description": "as-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator", + "description": "typeof-operator" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#type-conversion-exceptions-at-run-time", + "description": "type-conversion-exceptions" + } +] diff --git a/exercises/concept/casting/.docs/after.md b/exercises/concept/casting/.docs/after.md deleted file mode 100644 index 9745de8af6..0000000000 --- a/exercises/concept/casting/.docs/after.md +++ /dev/null @@ -1,155 +0,0 @@ -Casting and type conversion [are different ways of changing an expression from one data type to another][wiki-casting]. - -The [C# documentation][type-testing-and-cast-operators] classifies type conversion as the use of the [`as` operator][as-operator] or [`is` operator][is-operator]. Casting is defined as the use of the [cast operator][cast-operator]. - -In C# very often, outside of the realm of numeric values and class hierarchies, you will have to make a conversion by calling some member of the "to" type such as [`Int32.Parse()`][int32-parse] which converts a string to an integer or by calling a member of the "from" type e.g. `object.ToString()`. Javascript and developers in other dynamic languages should be aware. - -Note that implicit an explicit cast [operators][operator-overloading] (discussed in (TODO cross-ref-tba)) are available which can bring fairly arbitrary casting to your own types. - -#### Casting Primitive Types - Implicit - -C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. Note in the documentation the exception for converting to real numbers where precision may be lost. - -An implicit cast is not signified by any special syntax. For example: - -```csharp -int myInt = 1729; -long myLong = myInt; -``` - -There is no implicit conversion of a numeric (or string) expression to `bool`. The Base Class Library (BCL) provides `Convert.ToBoolean()` for this purpose. - -An expression of type `char` can be implicitly cast to `int`. The cast in the opposite direction must be explicit. Not all values of `int` are valid utf 16 chars. - -#### Casting Primitive Types - Explicit - -Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator]. - -Where the value being cast cannot be represented by the "to" type because it is insufficiently wide or there is a sign conflict then an overflow exception may be thrown in the case of integers, or the "to" type variable may take a value of `Infinity` in the case of floats and doubles. - -An expression of type `int` can be explicitly cast to `char`. This may result in an invalid `char`. - -#### Casting Primitive Types - Examples - -```csharp -int largeInt = Int32.MaxValue; -int largeNegInt = Int32.MinValue; -ushort shortUnsignedInt = ushort.MaxValue; -float largeFloat = float.MaxValue; -float smallFloat = 17.29f; - -// implicit cast -int from_ushort = shortUnsignedInt; // 65535 -float from_int = largeInt; // -21474836E+09 -int from_char = 'a'; // 96 - -// explicit cast -uint from_largeInt = (uint)largeInt; // 2147483647 -uint from_neg = (uint) largeNegInt; // 2147483648 or OverflowException is thrown (if checked) -int from_smallFloat = (int) smallFloat; // 17 -int from_largeFloat = (int) largeFloat; // -2147483648 or OverflowException is thrown (if checked) -char from_intc = (char) 32; // ' ' -char from_invalid_int = (char) 0xdcbf; // invalid char - no exception thrown - -// no cast available -int fromString = Int32.Parse("42"); // 42 -string toString = largeInt.ToString(); // "2147483647" -int fromString_bad = Int32.Parse("forty two"); // FormatException is thrown -``` - -See this [article][checked] for the _**checked**_ keyword. - -#### Type Conversion for types in a hierarchy - -Any type can be implicitly converted to its base class or interface. - -```csharp -IList ll = new List(); -``` - -A cast operator can be used to convert from a base to a derived class. - -```csharp -IList ll = new List(); -List l = (List)ll; -``` - -If the cast fails because the type of the expression being cast is not related to the type it is being cast to an instance of `InvalidCastException` is thrown. - -A more usual approach to these type conversions is to use the [`is`][is-operator] keyword: - -```csharp -interface IFoo { int Bar(); } -class Foo : IFoo { public int Bar() { return 42; }} -Object r = new Random(); -IFoo ifoo = new Foo(); -Object o = new Foo(); - -int result = 1729; - -if (ifoo is Foo foo) -{ - result = foo.Bar(); -} -// result == 42 - -result = 1729; -if (o is Foo foo2) -{ - result = foo2.Bar(); -} -// result == 42 - -result = 1729; -if (r is Foo foo3) -{ - result = foo3.Bar(); -} -// result == 1729 -``` - -The [`as`][as-operator] keyword fulfills a similar function to `is` e.g. `var foo = ifoo as Foo;`. In this example `foo` will be `null` if `ifoo` is not of type `Foo` otherwise `ifoo` will be assigned to it. - -#### Custom Cast Operator - -Types can define their own custom explicit and implicit [cast operators][custom-casts]. See (TODO cross-ref-tba) for coverage of this.. - -Examples of [explicit][big-integer-explicit] and [implicit][big-integer-implicit] casts in the BCL is conversions from the `BigInteger` struct to and from other numeric types - -#### Using `typeof` - -If you need to detect the precise type of an object then `is` may be a little too permissive as it will convert an object to a class or any of its base classes. `typeof` and `Object.GetType()` are the solution in this case. - -```csharp -object o = new List(); - -o is ICollection // true -o.GetType() == typeof(ICollection) // false -o is List // true -o.GetType() == typeof(List) // true -``` - -#### General - -- [Type testing and cast operators][type-testing-and-cast-operators]: introduction to type testing and casting. -- [cast operator][cast-operator]: the cast operator. -- [`is` operator][is-operator]: `is` operator reference. -- [`as`-operator][as-operator]: `as` operator reference. -- [`typeof` operator][typeof-operator]: `typeof` operator reference. -- [Type conversion exceptions][type-conversion-exceptions]: explains when a runtime exception is thrown when doing casts. - -[type-testing-and-cast-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast -[is-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#is-operator -[as-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#as-operator -[cast-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#cast-expression -[typeof-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/type-testing-and-cast#typeof-operator -[type-conversion-exceptions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/casting-and-type-conversions#type-conversion-exceptions-at-run-time -[wiki-casting]: https://en.wikipedia.org/wiki/Type_conversion -[implicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions -[explicit-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions -[int32-parse]: https://docs.microsoft.com/en-us/dotnet/api/system.int32.parse?view=netcore-3.1 -[operator-overloading]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/operator-overloading -[checked]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked -[custom-casts]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/user-defined-conversion-operators -[big-integer-implicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_implicit?view=netcore-3.1 -[big-integer-explicit]: https://docs.microsoft.com/en-us/dotnet/api/system.numerics.biginteger.op_explicit?view=netcore-3.1 From f2ec16079a8acc8d86c525527ff0595e1c6dada6 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:40:09 +0200 Subject: [PATCH 249/327] chars - replace about.md file with concept files * Pre-populate chars concept's about.md file from after.md file * Pre-populate chars concept's links.json file from after.md file * Pre-populate string-builder concept's about.md file from after.md file * Pre-populate string-builder concept's links.json file from after.md file * chars - Remove after.md document * Update about.md * Update about.md * Update links.json * Update about.md * Update links.json * [CI] Format code Co-authored-by: Mike May Co-authored-by: github-actions[bot] --- concepts/chars/about.md | 84 +++++++++++++++++++++++- concepts/chars/links.json | 67 ++++++++++++++++++- concepts/string-builder/about.md | 7 +- concepts/string-builder/links.json | 11 +++- exercises/concept/chars/.docs/after.md | 91 -------------------------- 5 files changed, 165 insertions(+), 95 deletions(-) delete mode 100644 exercises/concept/chars/.docs/after.md diff --git a/concepts/chars/about.md b/concepts/chars/about.md index 1314ebaf1b..6698111f2e 100644 --- a/concepts/chars/about.md +++ b/concepts/chars/about.md @@ -1 +1,83 @@ -TODO: add information on chars concept +`char`s are generally easy to use. They can be extracted from strings, added back +(by means of a string builder), defined and initialised using literals with single quotes, as in `char ch = 'A';` +, assigned and compared. + +General information on `char`s can be found here: + +- [Chars documentation][chars-docs]: reference documentation for `char`. +- [Chars tutorial][chars-tutorial]: basic tutorial on how to work with chars. + +However, `char`s have a number of rough edges as detailed below. +These rough edges mostly relate to the opposition +between the full unicode standard on the one side and historic representations +of text as well as performance and memory usage on the other. + +### Unicode Issues + +When dealing with strings, if `System.String` library methods are available you should +seek these out and use them rather than breaking the string down into characters. +Some textual "characters" consist of more than one `char` because the unicode standard +has more than 65536 code points. For instance the emojis that show up in some +of the tests have 2 `char`s as they comprise [surrogate][surrogates] characters. +Additionally, there are combining sequences for instance where in some cases +an accented character may consist of one `char` for the plain character +and another `char` for the accent. + +If you have to deal with individual characters you should try to use +library methods such as [`System.Char.IsControl`][is-control], [`System.Char.IsDigit`][is-digit] +rather than making naive comparisons such as checking that a character is +between '0' and '9'. For instance, note that '٢' is the arabic digit 2. `IsDigit` +will return true for the arabic version so you need to be clear say when validating +what range of inputs is acceptable. Even the `System.Char` library methods may not +behave as you would expect when you are dealing with more obscure languages. + +One way safely to break a string into display "characters" is to use [`StringInfo`][string-info] and +methods such as [`GetNexttextElement`][get-next-text-element]. This might be necessary if you are +dealing with globalization/localization. Another avenue where the scalar values +of unicode characters is important (say you are rolling your own encoding system) is to use +[runes][runes]. However, if you know the range of characters +you deal with does not include surrogates or combining character sequences (e.g. Latin ASCII) and your input +is well validated then you can avoid this. Again, the best position to be in +is where you can use `String`'s library methods. + +If you do find yourself in the unenviable position of dealing with the minutiae of unicode +then [this][char-encoding-net] is a good starting point. + +### Globalization + +If you are working in an environment where you are dealing with multiple cultures or +the culture is important in some parts of the code but not others then be +aware of the overloads of [`ToUpper`][to-upper] and [`ToLower`][to-lower] which take a culture and +[`ToUpperInvariant`][to-upper-invariant] and [`ToLowerInvariant`][to-lower-invariant] which will provide a consistent +result irrespective of the current [culture][culture-info]. + +### Representation, Characters and Integers + +Like other simple types (`int`s, `bool`s, etc.) the `char` has a companion +or alias type, in this case, `System.Char`. This is in fact a `struct` with +a 16 bit field. `char` in fact has some instance methods such as +`Equals`, `ToString` and [`CompareTo`][compare-to]. + +`char` has the same width as a [`ushort`][uint16] but they are generally +not used inter-changeably as they are in some languages. `ushort` has +to be explicitly cast to a `char`. For what it's worth `char`s can +be subject to arithmetic operations. The result of these operations is an integer. + +Obviously there is no equivalence between a `byte` at 8 bits and the 16 bit `char`. + +[chars-docs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char +[chars-tutorial]: https://csharp.net-tutorials.com/data-types/the-char-type/ +[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 +[uint16]: https://docs.microsoft.com/en-us/dotnet/api/system.uint16?view=netcore-3.1 +[string-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo?view=netcore-3.1 +[runes]: https://docs.microsoft.com/en-us/dotnet/api/system.text.rune?view=netcore-3.1 +[char-encoding-net]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding-introduction +[surrogates]: https://docs.microsoft.com/en-us/dotnet/api/system.char.issurrogate?view=netcore-3.1 +[is-control]: https://docs.microsoft.com/en-us/dotnet/api/system.char.iscontrol?view=netcore-3.1 +[to-upper]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupper?view=netcore-3.1#System_Char_ToUpper_System_Char_System_Globalization_CultureInfo_ +[to-lower]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolower?view=netcore-3.1#System_Char_ToLower_System_Char_System_Globalization_CultureInfo_ +[to-upper-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupperinvariant?view=netcore-3.1 +[to-lower-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolowerinvariant?view=netcore-3.1 +[is-digit]: https://docs.microsoft.com/en-us/dotnet/api/system.char.isdigit?view=netcore-3.1 +[get-next-text-element]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo.getnexttextelement?view=netcore-3.1 +[compare-to]: https://docs.microsoft.com/en-us/dotnet/api/system.char.compareto?view=netcore-3.1 diff --git a/concepts/chars/links.json b/concepts/chars/links.json index fe51488c70..891b2f7802 100644 --- a/concepts/chars/links.json +++ b/concepts/chars/links.json @@ -1 +1,66 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char", + "description": "chars-docs" + }, + { + "url": "https://csharp.net-tutorials.com/data-types/the-char-type/", + "description": "chars-tutorial" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.issurrogate?view=netcore-3.1", + "description": "surrogates" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.iscontrol?view=netcore-3.1", + "description": "is-control" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.isdigit?view=netcore-3.1", + "description": "is-digit" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo?view=netcore-3.1", + "description": "string-info" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo.getnexttextelement?view=netcore-3.1", + "description": "get-next-text-element" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.text.rune?view=netcore-3.1", + "description": "runes" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding-introduction", + "description": "char-encoding-net" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.toupper?view=netcore-3.1#System_Char_ToUpper_System_Char_System_Globalization_CultureInfo_", + "description": "to-upper" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.tolower?view=netcore-3.1#System_Char_ToLower_System_Char_System_Globalization_CultureInfo_", + "description": "to-lower" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.toupperinvariant?view=netcore-3.1", + "description": "to-upper-invariant" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.tolowerinvariant?view=netcore-3.1", + "description": "to-lower-invariant" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1", + "description": "culture-info" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.char.compareto?view=netcore-3.1", + "description": "compare-to" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.uint16?view=netcore-3.1", + "description": "uint16" + } +] diff --git a/concepts/string-builder/about.md b/concepts/string-builder/about.md index 3d56ed28b7..9efe3ba7ff 100644 --- a/concepts/string-builder/about.md +++ b/concepts/string-builder/about.md @@ -1 +1,6 @@ -TODO: add information on string-builder concept +Using `StringBuilder` is seen as hugely preferable to building up strings with multiple repeated concatenations with +a `+` or `+=` operator. Obviously simple one off concatenations are preferable +to instantiating a `StringBuilder` for clarity as well as performance. [This][skeet-stringbuilder] is what [Jon Skeet][so-jon-skeet] has to say about performance. + +[skeet-stringbuilder]: https://jonskeet.uk/csharp/stringbuilder.html +[so-jon-skeet]: https://stackoverflow.com/users/22656/jon-skeet diff --git a/concepts/string-builder/links.json b/concepts/string-builder/links.json index fe51488c70..a635ed13c1 100644 --- a/concepts/string-builder/links.json +++ b/concepts/string-builder/links.json @@ -1 +1,10 @@ -[] +[ + { + "url": "https://jonskeet.uk/csharp/stringbuilder.html", + "description": "skeet-stringbuilder" + }, + { + "url": "https://stackoverflow.com/users/22656/jon-skeet", + "description": "so-jon-skeet" + } +] diff --git a/exercises/concept/chars/.docs/after.md b/exercises/concept/chars/.docs/after.md deleted file mode 100644 index f6f788a8e3..0000000000 --- a/exercises/concept/chars/.docs/after.md +++ /dev/null @@ -1,91 +0,0 @@ -`char`s are generally easy to use. They can be extracted from strings, added back -(by means of a string builder), defined and initialised using literals with single quotes, as in `char ch = 'A';` -, assigned and compared. - -General information on `char`s can be found here: - -- [Chars documentation][chars-docs]: reference documentation for `char`. -- [Chars tutorial][chars-tutorial]: basic tutorial on how to work with chars. - -However, `char`s have a number of rough edges as detailed below. -These rough edges mostly relate to the opposition -between the full unicode standard on the one side and historic representations -of text as well as performance and memory usage on the other. - -### Unicode Issues - -When dealing with strings, if `System.String` library methods are available you should -seek these out and use them rather than breaking the string down into characters. -Some textual "characters" consist of more than one `char` because the unicode standard -has more than 65536 code points. For instance the emojis that show up in some -of the tests have 2 `char`s as they comprise [surrogate][surrogates] characters. -Additionally, there are combining sequences for instance where in some cases -an accented character may consist of one `char` for the plain character -and another `char` for the accent. - -If you have to deal with individual characters you should try to use -library methods such as [`System.Char.IsControl`][is-control], [`System.Char.IsDigit`][is-digit] -rather than making naive comparisons such as checking that a character is -between '0' and '9'. For instance, note that '٢' is the arabic digit 2. `IsDigit` -will return true for the arabic version so you need to be clear say when validating -what range of inputs is acceptable. Even the `System.Char` library methods may not -behave as you would expect when you are dealing with more obscure languages. - -One way safely to break a string into display "characters" is to use [`StringInfo`][string-info] and -methods such as [`GetNexttextElement`][get-next-text-element]. This might be necessary if you are -dealing with globalization/localization. Another avenue where the scalar values -of unicode characters is important (say you are rolling your own encoding system) is to use -[runes][runes]. However, if you know the range of characters -you deal with does not include surrogates or combining character sequences (e.g. Latin ASCII) and your input -is well validated then you can avoid this. Again, the best position to be in -is where you can use `String`'s library methods. - -If you do find yourself in the unenviable position of dealing with the minutiae of unicode -then [this][char-encoding-net] is a good starting point. - -### Globalization - -If you are working in an environment where you are dealing with multiple cultures or -the culture is important in some parts of the code but not others then be -aware of the overloads of [`ToUpper`][to-upper] and [`ToLower`][to-lower] which take a culture and -[`ToUpperInvariant`][to-upper-invariant] and [`ToLowerInvariant`][to-lower-invariant] which will provide a consistent -result irrespective of the current [culture][culture-info]. - -### Representation, Characters and Integers - -Like other simple types (`int`s, `bool`s, etc.) the `char` has a companion -or alias type, in this case, `System.Char`. This is in fact a `struct` with -a 16 bit field. `char` in fact has some instance methods such as -`Equals`, `ToString` and [`CompareTo`][compare-to]. - -`char` has the same width as a [`ushort`][uint16] but they are generally -not used inter-changeably as they are in some languages. `ushort` has -to be explicitly cast to a `char`. For what it's worth `char`s can -be subject to arithmetic operations. The result of these operations is an integer. - -Obviously there is no equivalence between a `byte` at 8 bits and the 16 bit `char`. - -### Performance - -Using `StringBuilder` is seen as hugely preferable to building up strings with multiple repeated concatenations with -a `+` or `+=` operator. Obviously simple one off concatenations are preferable -to instantiating a `StringBuilder` for clarity as well as performance. [This][skeet-stringbuilder] is what [Jon Skeet][so-jon-skeet] has to say about performance. - -[chars-docs]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/char -[chars-tutorial]: https://csharp.net-tutorials.com/data-types/the-char-type/ -[culture-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.cultureinfo?view=netcore-3.1 -[uint16]: https://docs.microsoft.com/en-us/dotnet/api/system.uint16?view=netcore-3.1 -[string-info]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo?view=netcore-3.1 -[runes]: https://docs.microsoft.com/en-us/dotnet/api/system.text.rune?view=netcore-3.1 -[char-encoding-net]: https://docs.microsoft.com/en-us/dotnet/standard/base-types/character-encoding-introduction -[surrogates]: https://docs.microsoft.com/en-us/dotnet/api/system.char.issurrogate?view=netcore-3.1 -[is-control]: https://docs.microsoft.com/en-us/dotnet/api/system.char.iscontrol?view=netcore-3.1 -[to-upper]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupper?view=netcore-3.1#System_Char_ToUpper_System_Char_System_Globalization_CultureInfo_ -[to-lower]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolower?view=netcore-3.1#System_Char_ToLower_System_Char_System_Globalization_CultureInfo_ -[to-upper-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.toupperinvariant?view=netcore-3.1 -[to-lower-invariant]: https://docs.microsoft.com/en-us/dotnet/api/system.char.tolowerinvariant?view=netcore-3.1 -[is-digit]: https://docs.microsoft.com/en-us/dotnet/api/system.char.isdigit?view=netcore-3.1 -[get-next-text-element]: https://docs.microsoft.com/en-us/dotnet/api/system.globalization.stringinfo.getnexttextelement?view=netcore-3.1 -[compare-to]: https://docs.microsoft.com/en-us/dotnet/api/system.char.compareto?view=netcore-3.1 -[skeet-stringbuilder]: https://jonskeet.uk/csharp/stringbuilder.html -[so-jon-skeet]: https://stackoverflow.com/users/22656/jon-skeet From f604a374c30ffb99e7d0571e50394891eb84ebd4 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 22 Oct 2020 16:40:32 +0200 Subject: [PATCH 250/327] arrays - replace about.md file with concept files * Pre-populate arrays concept's about.md file from after.md file * Pre-populate arrays concept's links.json file from after.md file * Pre-populate for-loops concept's about.md file from after.md file * Pre-populate for-loops concept's links.json file from after.md file * Pre-populate foreach-loops concept's about.md file from after.md file * Pre-populate foreach-loops concept's links.json file from after.md file * arrays - Remove after.md document * Update about.md * Update about.md * Update about.md * [CI] Format code Co-authored-by: Mike May Co-authored-by: github-actions[bot] --- concepts/arrays/about.md | 102 +++++++++++++++++++++++- concepts/arrays/links.json | 31 ++++++- concepts/for-loops/about.md | 102 +++++++++++++++++++++++- concepts/for-loops/links.json | 31 ++++++- concepts/foreach-loops/about.md | 102 +++++++++++++++++++++++- concepts/foreach-loops/links.json | 31 ++++++- exercises/concept/arrays/.docs/after.md | 100 ----------------------- 7 files changed, 393 insertions(+), 106 deletions(-) delete mode 100644 exercises/concept/arrays/.docs/after.md diff --git a/concepts/arrays/about.md b/concepts/arrays/about.md index c54a50ebfc..b46d9d77d7 100644 --- a/concepts/arrays/about.md +++ b/concepts/arrays/about.md @@ -1 +1,101 @@ -TODO: add information on arrays concept +TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts. +Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: + +```csharp +// Declare array with explicit size (size is 2) +int[] twoInts = new int[2]; + +// Assign second element by index +twoInts[1] = 8; + +// Retrieve the second element by index +twoInts[1] == 8; // => true + +// Check the length of the array +twoInts.Length == 2; // => true +``` + +Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: + +```csharp +// Three equivalent ways to declare and initialize an array (size is 3) +int[] threeIntsV1 = new int[] { 4, 9, 7 }; +int[] threeIntsV2 = new[] { 4, 9, 7 }; +int[] threeIntsV3 = { 4, 9, 7 }; +``` + +Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. + +An array is also a _collection_, which means that you can iterate over _all_ its values using a [`foreach` loop][foreach-statement]: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // Output the vowel + System.Console.Write(vowel); +} + +// => aeiou +``` + +One could use a [`for` loop][for-statement] to iterate over an array: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +for (int i = 0; i < vowels.Length; i++) +{ + // Output the vowel + System.Console.Write(vowels[i]); +} + +// => aeiou +``` + +However, generally a `foreach` loop is preferrable over a `for` loop for the following reasons: + +- A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. +- A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. +- A `foreach` loop is foolproof, whereas with `for` loops it is easy to have an off-by-one error. +- A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. + +To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // This would result in a compiler error + // vowel = 'Y'; +} +``` + +A `for` loop does have some advantages over a `foreach` loop: + +- You can start or stop at the index you want. +- You can use any (boolean) termination condition you want. +- You can skip elements by customizing the incrementing of the loop variable. +- You can process collections from back to front by counting down. +- You can use `for` loops in scenarios that don't involve collections. + +Related Topics: + +- You should be aware that C# supports [multi-dimensional arrays][multi-dimensional-arrays] like `int[,] arr = new int[10, 5]` which can be very useful. +- You should also be aware that you can instantiate objects of type [`System.Array`][system-array-object] with `Array.CreateInstance`. Such objects are of little use - mainly for interop with VB.NET code. They are not interchangeable with standard arrays (`T[]`). They can have a non-zero lower bound. + +Both the above topics are discussed more fully in a later exercise. + +[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[array-class]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 +[array-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties +[array-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods +[foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in +[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for +[break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[multi-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays +[system-array-object]: https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_ diff --git a/concepts/arrays/links.json b/concepts/arrays/links.json index fe51488c70..f552d50831 100644 --- a/concepts/arrays/links.json +++ b/concepts/arrays/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods", + "description": "array-methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties", + "description": "array-properties" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1", + "description": "array-class" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in", + "description": "foreach-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for", + "description": "for-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays", + "description": "multi-dimensional-arrays" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_", + "description": "system-array-object" + } +] diff --git a/concepts/for-loops/about.md b/concepts/for-loops/about.md index d16625c977..b46d9d77d7 100644 --- a/concepts/for-loops/about.md +++ b/concepts/for-loops/about.md @@ -1 +1,101 @@ -TODO: add information on for-loops concept +TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts. +Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: + +```csharp +// Declare array with explicit size (size is 2) +int[] twoInts = new int[2]; + +// Assign second element by index +twoInts[1] = 8; + +// Retrieve the second element by index +twoInts[1] == 8; // => true + +// Check the length of the array +twoInts.Length == 2; // => true +``` + +Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: + +```csharp +// Three equivalent ways to declare and initialize an array (size is 3) +int[] threeIntsV1 = new int[] { 4, 9, 7 }; +int[] threeIntsV2 = new[] { 4, 9, 7 }; +int[] threeIntsV3 = { 4, 9, 7 }; +``` + +Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. + +An array is also a _collection_, which means that you can iterate over _all_ its values using a [`foreach` loop][foreach-statement]: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // Output the vowel + System.Console.Write(vowel); +} + +// => aeiou +``` + +One could use a [`for` loop][for-statement] to iterate over an array: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +for (int i = 0; i < vowels.Length; i++) +{ + // Output the vowel + System.Console.Write(vowels[i]); +} + +// => aeiou +``` + +However, generally a `foreach` loop is preferrable over a `for` loop for the following reasons: + +- A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. +- A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. +- A `foreach` loop is foolproof, whereas with `for` loops it is easy to have an off-by-one error. +- A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. + +To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // This would result in a compiler error + // vowel = 'Y'; +} +``` + +A `for` loop does have some advantages over a `foreach` loop: + +- You can start or stop at the index you want. +- You can use any (boolean) termination condition you want. +- You can skip elements by customizing the incrementing of the loop variable. +- You can process collections from back to front by counting down. +- You can use `for` loops in scenarios that don't involve collections. + +Related Topics: + +- You should be aware that C# supports [multi-dimensional arrays][multi-dimensional-arrays] like `int[,] arr = new int[10, 5]` which can be very useful. +- You should also be aware that you can instantiate objects of type [`System.Array`][system-array-object] with `Array.CreateInstance`. Such objects are of little use - mainly for interop with VB.NET code. They are not interchangeable with standard arrays (`T[]`). They can have a non-zero lower bound. + +Both the above topics are discussed more fully in a later exercise. + +[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[array-class]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 +[array-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties +[array-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods +[foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in +[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for +[break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[multi-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays +[system-array-object]: https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_ diff --git a/concepts/for-loops/links.json b/concepts/for-loops/links.json index fe51488c70..f552d50831 100644 --- a/concepts/for-loops/links.json +++ b/concepts/for-loops/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods", + "description": "array-methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties", + "description": "array-properties" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1", + "description": "array-class" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in", + "description": "foreach-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for", + "description": "for-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays", + "description": "multi-dimensional-arrays" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_", + "description": "system-array-object" + } +] diff --git a/concepts/foreach-loops/about.md b/concepts/foreach-loops/about.md index 704f42cd36..b46d9d77d7 100644 --- a/concepts/foreach-loops/about.md +++ b/concepts/foreach-loops/about.md @@ -1 +1,101 @@ -TODO: add information on foreach-loops concept +TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts. +Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: + +```csharp +// Declare array with explicit size (size is 2) +int[] twoInts = new int[2]; + +// Assign second element by index +twoInts[1] = 8; + +// Retrieve the second element by index +twoInts[1] == 8; // => true + +// Check the length of the array +twoInts.Length == 2; // => true +``` + +Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: + +```csharp +// Three equivalent ways to declare and initialize an array (size is 3) +int[] threeIntsV1 = new int[] { 4, 9, 7 }; +int[] threeIntsV2 = new[] { 4, 9, 7 }; +int[] threeIntsV3 = { 4, 9, 7 }; +``` + +Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. + +An array is also a _collection_, which means that you can iterate over _all_ its values using a [`foreach` loop][foreach-statement]: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // Output the vowel + System.Console.Write(vowel); +} + +// => aeiou +``` + +One could use a [`for` loop][for-statement] to iterate over an array: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +for (int i = 0; i < vowels.Length; i++) +{ + // Output the vowel + System.Console.Write(vowels[i]); +} + +// => aeiou +``` + +However, generally a `foreach` loop is preferrable over a `for` loop for the following reasons: + +- A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. +- A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. +- A `foreach` loop is foolproof, whereas with `for` loops it is easy to have an off-by-one error. +- A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. + +To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: + +```csharp +char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; + +foreach (char vowel in vowels) +{ + // This would result in a compiler error + // vowel = 'Y'; +} +``` + +A `for` loop does have some advantages over a `foreach` loop: + +- You can start or stop at the index you want. +- You can use any (boolean) termination condition you want. +- You can skip elements by customizing the incrementing of the loop variable. +- You can process collections from back to front by counting down. +- You can use `for` loops in scenarios that don't involve collections. + +Related Topics: + +- You should be aware that C# supports [multi-dimensional arrays][multi-dimensional-arrays] like `int[,] arr = new int[10, 5]` which can be very useful. +- You should also be aware that you can instantiate objects of type [`System.Array`][system-array-object] with `Array.CreateInstance`. Such objects are of little use - mainly for interop with VB.NET code. They are not interchangeable with standard arrays (`T[]`). They can have a non-zero lower bound. + +Both the above topics are discussed more fully in a later exercise. + +[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays +[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays +[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays +[array-class]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 +[array-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties +[array-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods +[foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in +[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for +[break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[multi-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays +[system-array-object]: https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_ diff --git a/concepts/foreach-loops/links.json b/concepts/foreach-loops/links.json index fe51488c70..f552d50831 100644 --- a/concepts/foreach-loops/links.json +++ b/concepts/foreach-loops/links.json @@ -1 +1,30 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods", + "description": "array-methods" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties", + "description": "array-properties" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1", + "description": "array-class" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in", + "description": "foreach-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for", + "description": "for-statement" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays", + "description": "multi-dimensional-arrays" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_", + "description": "system-array-object" + } +] diff --git a/exercises/concept/arrays/.docs/after.md b/exercises/concept/arrays/.docs/after.md deleted file mode 100644 index 4d5bc15209..0000000000 --- a/exercises/concept/arrays/.docs/after.md +++ /dev/null @@ -1,100 +0,0 @@ -Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: - -```csharp -// Declare array with explicit size (size is 2) -int[] twoInts = new int[2]; - -// Assign second element by index -twoInts[1] = 8; - -// Retrieve the second element by index -twoInts[1] == 8; // => true - -// Check the length of the array -twoInts.Length == 2; // => true -``` - -Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted: - -```csharp -// Three equivalent ways to declare and initialize an array (size is 3) -int[] threeIntsV1 = new int[] { 4, 9, 7 }; -int[] threeIntsV2 = new[] { 4, 9, 7 }; -int[] threeIntsV3 = { 4, 9, 7 }; -``` - -Arrays can be manipulated by either calling an array instance's [methods][array-methods] or [properties][array-properties], or by using the static methods defined in the [`Array` class][array-class]. - -An array is also a _collection_, which means that you can iterate over _all_ its values using a [`foreach` loop][foreach-statement]: - -```csharp -char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; - -foreach (char vowel in vowels) -{ - // Output the vowel - System.Console.Write(vowel); -} - -// => aeiou -``` - -One could use a [`for` loop][for-statement] to iterate over an array: - -```csharp -char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; - -for (int i = 0; i < vowels.Length; i++) -{ - // Output the vowel - System.Console.Write(vowels[i]); -} - -// => aeiou -``` - -However, generally a `foreach` loop is preferrable over a `for` loop for the following reasons: - -- A `foreach` loop is guaranteed to iterate over _all_ values. With a `for` loop, it is easy to miss elements, for example due to an off-by-one error. -- A `foreach` loop is more _declarative_, your code is communicating _what_ you want it to do, instead of a `for` loop that communicates _how_ you want to do it. -- A `foreach` loop is foolproof, whereas with `for` loops it is easy to have an off-by-one error. -- A `foreach` loop works on all collection types, including those that don't support using an indexer to access elements. - -To guarantee that a `foreach` loop will iterate over _all_ values, the compiler will not allow updating of a collection within a `foreach` loop: - -```csharp -char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' }; - -foreach (char vowel in vowels) -{ - // This would result in a compiler error - // vowel = 'Y'; -} -``` - -A `for` loop does have some advantages over a `foreach` loop: - -- You can start or stop at the index you want. -- You can use any (boolean) termination condition you want. -- You can skip elements by customizing the incrementing of the loop variable. -- You can process collections from back to front by counting down. -- You can use `for` loops in scenarios that don't involve collections. - -Related Topics: - -- You should be aware that C# supports [multi-dimensional arrays][multi-dimensional-arrays] like `int[,] arr = new int[10, 5]` which can be very useful. -- You should also be aware that you can instantiate objects of type [`System.Array`][system-array-object] with `Array.CreateInstance`. Such objects are of little use - mainly for interop with VB.NET code. They are not interchangeable with standard arrays (`T[]`). They can have a non-zero lower bound. - -Both the above topics are discussed more fully in a later exercise. - -[implicitly-typed-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/implicitly-typed-arrays -[array-foreach]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/using-foreach-with-arrays -[single-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/single-dimensional-arrays -[array-class]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1 -[array-properties]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#properties -[array-methods]: https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netcore-3.1#methods -[foreach-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/foreach-in -[for-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/for -[break-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break -[multi-dimensional-arrays]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/arrays/multidimensional-arrays -[system-array-object]: https://docs.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=netcore-3.1#System_Array_CreateInstance_System_Type_System_Int32_ From aa74e74e39251bf8b009c17b444884b0e91160e9 Mon Sep 17 00:00:00 2001 From: Mike May Date: Tue, 27 Oct 2020 05:35:32 -0400 Subject: [PATCH 251/327] switch-statements - (manual) replace about.md file with concept files manual construction of about.md to avoid merge conflicts manual construction of about.md to avoid merge conflicts --- concepts/switch-statements/about.md | 64 ++++++++++++++++++- concepts/switch-statements/links.json | 43 ++++++++++++- .../concept/switch-statements/.docs/after.md | 63 ------------------ 3 files changed, 105 insertions(+), 65 deletions(-) delete mode 100644 exercises/concept/switch-statements/.docs/after.md diff --git a/concepts/switch-statements/about.md b/concepts/switch-statements/about.md index 3179a5c212..8261c86e02 100644 --- a/concepts/switch-statements/about.md +++ b/concepts/switch-statements/about.md @@ -1 +1,63 @@ -TODO: add information on switch-statements concept +Switch statements have a venerable [history][wiki-switch] in programming languages. They were introduced in [`C`][c-switch] where they were prized for their speed. That speed came at the cost of functionality which was very constrained. In C# the role of the switch statement has been expanded beyond integers. Switch statements can encompass any arbitrary type, value or reference. + +If you are coming from a functional language then working with switch statements (and [switch expressions][switch-expression] discussed elsewhere) is the nearest you will get in C# to using discriminated unions and pattern matching. However, they have nowhere near the discriminated union's power to enforce type safety. + +Simple switch statements resemble their `C` ancestors combining [`switch`][switch], [`case`][case], [`break`][switch-break] and [`default`][switch-default]. + +```csharp +int direction = GetDirection(); +switch (direction) +{ + case 1: + GoLeft(); + break; + case 2: + GoRight(); + break; + default: + MarkTime(); + break; +} +``` + +The above pattern can be used with any simple (primitives + strings) type. + +When reference types are added into the mix then [extra syntax][switch-pattern-matching] is involved, firstly to down cast the type and then to add guards ([`when`][switch-when]) although guards can be used with simple value cases. This is illustrated below: + +```csharp +Animal animal = GetAnimal(); + +switch(animal) +{ + case Dog canine: + case Coyote canine: + canine.Bark(); + break; + case Cat cat when cat.HasOnly8Lives(): + cat.IsCareful(); + cat.Meow(); + break; + case Cat cat: + cat.Meow(); + break; +} +``` + +- The `default` clause is optional but typically desirable. +- The `break` statement is mandatory for any non-empty `case` clause. +- Obviously the type of all the arguments to the `case` labels must be derived from the type of the `switch` argument. A `switch` argument of type `Object` obviously allows the widest range. +- The guard expression can include anything in scope not just members of the `case` argument. +- Multiple `case` with different `case` arguments can refer to the same code block. + +[switch statement][switch-statement] documentation provides an introduction to `switch` statements. + +[wiki-switch]: https://en.wikipedia.org/wiki/Switch_statement +[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch +[switch-expression]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#basic-example +[switch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-switch-section +[case]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#case-labels +[switch-break]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break +[switch-default]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case +[switch-pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern +[switch-when]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-case-statement-and-the-when-clause +[c-switch]: https://docs.microsoft.com/en-us/cpp/c-language/switch-statement-c?view=vs-2019 diff --git a/concepts/switch-statements/links.json b/concepts/switch-statements/links.json index fe51488c70..83ab8bf9cf 100644 --- a/concepts/switch-statements/links.json +++ b/concepts/switch-statements/links.json @@ -1 +1,42 @@ -[] +[ + { + "url": "https://en.wikipedia.org/wiki/Switch_statement", + "description": "wiki-switch" + }, + { + "url": "https://docs.microsoft.com/en-us/cpp/c-language/switch-statement-c?view=vs-2019", + "description": "c-switch" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#basic-example", + "description": "switch-expression" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-switch-section", + "description": "switch" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#case-labels", + "description": "case" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break", + "description": "switch-break" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case", + "description": "switch-default" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern", + "description": "switch-pattern-matching" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-case-statement-and-the-when-clause", + "description": "switch-when" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch", + "description": "switch-statement" + } +] diff --git a/exercises/concept/switch-statements/.docs/after.md b/exercises/concept/switch-statements/.docs/after.md deleted file mode 100644 index 8261c86e02..0000000000 --- a/exercises/concept/switch-statements/.docs/after.md +++ /dev/null @@ -1,63 +0,0 @@ -Switch statements have a venerable [history][wiki-switch] in programming languages. They were introduced in [`C`][c-switch] where they were prized for their speed. That speed came at the cost of functionality which was very constrained. In C# the role of the switch statement has been expanded beyond integers. Switch statements can encompass any arbitrary type, value or reference. - -If you are coming from a functional language then working with switch statements (and [switch expressions][switch-expression] discussed elsewhere) is the nearest you will get in C# to using discriminated unions and pattern matching. However, they have nowhere near the discriminated union's power to enforce type safety. - -Simple switch statements resemble their `C` ancestors combining [`switch`][switch], [`case`][case], [`break`][switch-break] and [`default`][switch-default]. - -```csharp -int direction = GetDirection(); -switch (direction) -{ - case 1: - GoLeft(); - break; - case 2: - GoRight(); - break; - default: - MarkTime(); - break; -} -``` - -The above pattern can be used with any simple (primitives + strings) type. - -When reference types are added into the mix then [extra syntax][switch-pattern-matching] is involved, firstly to down cast the type and then to add guards ([`when`][switch-when]) although guards can be used with simple value cases. This is illustrated below: - -```csharp -Animal animal = GetAnimal(); - -switch(animal) -{ - case Dog canine: - case Coyote canine: - canine.Bark(); - break; - case Cat cat when cat.HasOnly8Lives(): - cat.IsCareful(); - cat.Meow(); - break; - case Cat cat: - cat.Meow(); - break; -} -``` - -- The `default` clause is optional but typically desirable. -- The `break` statement is mandatory for any non-empty `case` clause. -- Obviously the type of all the arguments to the `case` labels must be derived from the type of the `switch` argument. A `switch` argument of type `Object` obviously allows the widest range. -- The guard expression can include anything in scope not just members of the `case` argument. -- Multiple `case` with different `case` arguments can refer to the same code block. - -[switch statement][switch-statement] documentation provides an introduction to `switch` statements. - -[wiki-switch]: https://en.wikipedia.org/wiki/Switch_statement -[switch-statement]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch -[switch-expression]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/switch-expression#basic-example -[switch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-switch-section -[case]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#case-labels -[switch-break]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/break -[switch-default]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case -[switch-pattern-matching]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#type-pattern -[switch-when]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-case-statement-and-the-when-clause -[c-switch]: https://docs.microsoft.com/en-us/cpp/c-language/switch-statement-c?view=vs-2019 From fcbf2bb45b780e4664d60bd6cb102ad400dd7e8f Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Tue, 27 Oct 2020 13:35:21 +0100 Subject: [PATCH 252/327] Fix typos * fixing typos and Prerequisites * run prettier * remove anoying submodule --- concepts/interfaces/about.md | 2 +- concepts/properties/about.md | 8 ++++---- exercises/concept/dictionaries/.docs/instructions.md | 6 +++--- exercises/concept/dictionaries/.docs/introduction.md | 2 +- exercises/concept/equality/.docs/instructions.md | 6 +++--- exercises/concept/equality/.meta/design.md | 2 +- exercises/concept/exceptions/.meta/design.md | 2 +- .../concept/expression-bodied-members/.meta/design.md | 2 +- exercises/concept/flag-enums/.docs/introduction.md | 2 +- exercises/concept/interfaces/.meta/design.md | 2 +- exercises/concept/nullability/.meta/design.md | 4 ++-- exercises/concept/object-initializers/.docs/hints.md | 2 +- .../concept/operator-overloading/.docs/introduction.md | 2 +- exercises/concept/properties/.docs/introduction.md | 2 +- exercises/concept/properties/.meta/design.md | 2 +- .../concept/regular-expressions/.docs/instructions.md | 6 +++--- exercises/concept/resource-cleanup/.docs/instructions.md | 4 ++-- exercises/concept/resource-cleanup/.meta/design.md | 2 +- exercises/concept/resource-lifetime/.docs/introduction.md | 2 +- exercises/concept/time/.docs/instructions.md | 2 +- exercises/concept/tuples/.docs/introduction.md | 6 +++--- 21 files changed, 34 insertions(+), 34 deletions(-) diff --git a/concepts/interfaces/about.md b/concepts/interfaces/about.md index 771fe01c66..fecb4c8ef8 100644 --- a/concepts/interfaces/about.md +++ b/concepts/interfaces/about.md @@ -109,7 +109,7 @@ Interfaces can inherit from other interfaces. Members of an interface are public by default. -Interfaces can contain nested types, such as `const` literals, `enums`, `delegates`, `classes` and `structs`. Here, the interfaces act as [namespaces][wiki-namespaces] in the same way that classes and structs do and the behaviour and syntax is identical. +Interfaces can contain nested types, such as `const` literals, `enums`, `delegates`, `classes` and `structs`. Here, the interfaces act as [namespaces][wiki-namespaces] in the same way that classes and structs do and the behavior and syntax is identical. By design, C# does not support multiple inheritance, but it facilitates a kind of multiple inheritance through interfaces. diff --git a/concepts/properties/about.md b/concepts/properties/about.md index 7882cf52a1..dd33bc01ee 100644 --- a/concepts/properties/about.md +++ b/concepts/properties/about.md @@ -16,11 +16,11 @@ The two main types of property are } ``` -There is considerable overlap of behaviour and power between properties and methods. +There is considerable overlap of behavior and power between properties and methods. When they are not auto-implemented properties can contain any statement or expression that can appear within the scope of the class. In a common case they are often described as wrapping a backing field. -Although much of the time it is obvious whether to code behaviour as a property or method in a particular case it is +Although much of the time it is obvious whether to code behavior as a property or method in a particular case it is often a judgement call for the coder and in particular how much code should be executed within the accessors. Validation in a set accessor and simple calculation or formatting in a get accessor are commonly found: @@ -55,7 +55,7 @@ public int ConfidentialValueUsedInternally {private get; set; } ``` Non-public set accessors are also supported but a more common case is where -the set accessor may be ommitted completely. This is maybe because +the set accessor may be omitted completely. This is maybe because the value of the property is set in the class's constructor. ```csharp @@ -74,7 +74,7 @@ topics in other exercises: - expression bodied properties, get accessors and set accessors (covered by expression-bodied members) - properties on interfaces (covered by Interfaces) -- properties/absract properties on abstract classes (covered by Inheritance) +- properties/abstract properties on abstract classes (covered by Inheritance) - use of the `readonly` keyword with properties (covered by Immutability) - static properties (covered by Statics) - indexers (covered by Indexers) diff --git a/exercises/concept/dictionaries/.docs/instructions.md b/exercises/concept/dictionaries/.docs/instructions.md index d63b7de736..143797402b 100644 --- a/exercises/concept/dictionaries/.docs/instructions.md +++ b/exercises/concept/dictionaries/.docs/instructions.md @@ -13,7 +13,7 @@ DialingCodes.GetEmptyDictionary(); ### 2. Create a pre-populated dictionary -There exists a pre-populated dictionary which contains the following 3 dialing codes: "United States of America" which has a code of 1, "Brazil" which has a code of 55 and "India" which has a code of 91. Implement the (static) `DialingCodes.GetExistingDictionary()` method to return the pre-propulated dictionary: +There exists a pre-populated dictionary which contains the following 3 dialing codes: "United States of America" which has a code of 1, "Brazil" which has a code of 55 and "India" which has a code of 91. Implement the (static) `DialingCodes.GetExistingDictionary()` method to return the pre-populated dictionary: ```csharp DialingCodes.GetExistingDictionary(); @@ -29,9 +29,9 @@ DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); // 44 => "United Kingdom" ``` -### 4. Add a country to an dxisting dictionary +### 4. Add a country to an existing dictionary -Add "United Kindom" with a dialing code of 44 to the dictionary created in task 2: +Add "United Kingdom" with a dialing code of 44 to the dictionary created in task 2: ```csharp DialingCodes.AddCountryToExistingDictionary(DialingCodes.GetExistingDictionary(), diff --git a/exercises/concept/dictionaries/.docs/introduction.md b/exercises/concept/dictionaries/.docs/introduction.md index 5619ea3abd..937cf345d3 100644 --- a/exercises/concept/dictionaries/.docs/introduction.md +++ b/exercises/concept/dictionaries/.docs/introduction.md @@ -1,4 +1,4 @@ -A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the ditionary its associated value is returned. It has the same role as maps or associative arrays do in other languages. +A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages. A dictionary can be created as follows: diff --git a/exercises/concept/equality/.docs/instructions.md b/exercises/concept/equality/.docs/instructions.md index 25dcc2cde7..24aa084feb 100644 --- a/exercises/concept/equality/.docs/instructions.md +++ b/exercises/concept/equality/.docs/instructions.md @@ -6,7 +6,7 @@ In all occurrences the eye color parameter is guaranteed to be non-null. Implement `Authenticator.AreSameFace()` to check that two faces match. -Add equality reoutines for the `FacialFeatures` class. +Add equality routines for the `FacialFeatures` class. ```csharp Authenticator.AreSameFace(new FacialFeatures("green", 0.9m), new FacialFeatures("green", 0.9m); @@ -45,7 +45,7 @@ authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFe ## 3. Register new identities -Implement the `Authenticator.Register()` method which stores an identity on the authenticator itself such that calls to `IsRegistered()` will return `true` for this identity: otherwise `IsRegisterd()` returns `false`. +Implement the `Authenticator.Register()` method which stores an identity on the authenticator itself such that calls to `IsRegistered()` will return `true` for this identity: otherwise `IsRegistered()` returns `false`. To detect duplicated attempts to register an identity, if the identity has already been registered then `false` is returned by `Authenticator.Register()`, otherwise `true`. @@ -71,7 +71,7 @@ authenticator.IsRegistered(new Identity("alice@thecompetition.com", new FacialFe ## 5. Add diagnostics to detect multiple attempts to authenticate -A bug has been reported whereby the `Authenticator.IsRegistered()` nethod is called multiple times in quick succession for the same identity. You believe that there is some sort of "bounce" problem where the exact same record is being submitted multiple times. Your task is to add a diagnostic routine `Authenticator.AreSameObject()` to support any testing that's undertaken. The routine compares to objects and returns `true` if they are the exact same instance otherwise `false`. +A bug has been reported whereby the `Authenticator.IsRegistered()` method is called multiple times in quick succession for the same identity. You believe that there is some sort of "bounce" problem where the exact same record is being submitted multiple times. Your task is to add a diagnostic routine `Authenticator.AreSameObject()` to support any testing that's undertaken. The routine compares to objects and returns `true` if they are the exact same instance otherwise `false`. ```csharp var identityA = new Identity("alice@thecompetition.com", new FacialFeatures("blue", 0.9m)); diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/equality/.meta/design.md index 6c0cb8353c..b037290b70 100644 --- a/exercises/concept/equality/.meta/design.md +++ b/exercises/concept/equality/.meta/design.md @@ -17,7 +17,7 @@ This Concepts Exercise's Concepts are: - `equality`: know how to check for equality and inequality; know how reference equality differs from structural equality; know that equality works by default for value and reference types; know how to customize equality checks using `Equals` and `GetHashCode()`; know of the `IEquatable` and `IEqualityComparer` interfaces and how to implement them. -- `sets`: Know how to use hash sets `HashSet` as provided by the .NET BCL. Understand the relationship with `Object.GetHashCode()` and the performance charateristics of hash sets. +- `sets`: Know how to use hash sets `HashSet` as provided by the .NET BCL. Understand the relationship with `Object.GetHashCode()` and the performance characteristics of hash sets. - `marker-interfaces`: know what a marker interface is; know of some common marker interfaces ## Prerequisites diff --git a/exercises/concept/exceptions/.meta/design.md b/exercises/concept/exceptions/.meta/design.md index 540a0a9550..3c822196ba 100644 --- a/exercises/concept/exceptions/.meta/design.md +++ b/exercises/concept/exceptions/.meta/design.md @@ -21,7 +21,7 @@ The goal of this exercise is to teach the student the Concept of Exceptions in C - `exceptions`: know what exceptions are; know when an exception should be thrown; know how to throw (and rethrow) an exception; know how to catch an exception; know the most important built-in exceptions (`ArgumentException`, `InvalidOperationException`). -## Prequisites +## Prerequisites - `basics`: know how to do string interpolation and how to work with `int`s - `inheritance`: know about class hierarchies diff --git a/exercises/concept/expression-bodied-members/.meta/design.md b/exercises/concept/expression-bodied-members/.meta/design.md index 1e67ebe39b..d3e067ea36 100644 --- a/exercises/concept/expression-bodied-members/.meta/design.md +++ b/exercises/concept/expression-bodied-members/.meta/design.md @@ -28,4 +28,4 @@ - `if-statements` - `exceptions` - `switch statements`: background for `switch expressions`. -- `datetimes`: `DateTiime.Now` is used in example code. +- `datetimes`: `DateTime.Now` is used in example code. diff --git a/exercises/concept/flag-enums/.docs/introduction.md b/exercises/concept/flag-enums/.docs/introduction.md index 8a354a7c6c..2f383b1e22 100644 --- a/exercises/concept/flag-enums/.docs/introduction.md +++ b/exercises/concept/flag-enums/.docs/introduction.md @@ -20,7 +20,7 @@ To work with bits, C# supports the following operators: - `>>`: right shift - `&`: logical AND - `|`: logical OR -- `^`: logial XOR +- `^`: logical XOR Here is an example how to use a bitwise operator: diff --git a/exercises/concept/interfaces/.meta/design.md b/exercises/concept/interfaces/.meta/design.md index f559772c9a..b04f01ccb6 100644 --- a/exercises/concept/interfaces/.meta/design.md +++ b/exercises/concept/interfaces/.meta/design.md @@ -11,7 +11,7 @@ ## Concepts - `interfaces`: know what interfaces are; know how to use interfaces; know how to define an interface; know how to implement an interface; know how to explicitly implement an interface. -- `ordering` : know how to implement the `IComparable` interface and what its effect is on the behaviour of collections. +- `ordering` : know how to implement the `IComparable` interface and what its effect is on the behavior of collections. - `explicit-interfaces`: know how an explicit interface is declared; know how use an explicit interface; know why explicit interfaces are useful ## Prerequisites diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/nullability/.meta/design.md index ec4b5cb578..7490c2a55f 100644 --- a/exercises/concept/nullability/.meta/design.md +++ b/exercises/concept/nullability/.meta/design.md @@ -20,8 +20,8 @@ - `nullability`: know of the existence of the `null` literal; know what a `NullReferenceException` is and when it is thrown; know how to compare a value to `null`; know the difference between value and reference types regarding nullability; know how to define nullable reference and value types; know about the null-related operators; know about basic null checking by the compiler. - `null-coalescing`: know the syntax and behavior of the null-coalescing operator (??) - `null-conditional`: know the syntax and behavior of the null-conditional operator (?.) -- `null-forgiving`: know the syntax and behvior of the null-forgiving operator (!.); know to use the operator with discretion -- `nullable-values`: know wbout nullable primitives; know about nullable structs +- `null-forgiving`: know the syntax and behavior of the null-forgiving operator (!.); know to use the operator with discretion +- `nullable-values`: know about nullable primitives; know about nullable structs ## Prerequisites diff --git a/exercises/concept/object-initializers/.docs/hints.md b/exercises/concept/object-initializers/.docs/hints.md index 558b61e016..bafc7d1cc9 100644 --- a/exercises/concept/object-initializers/.docs/hints.md +++ b/exercises/concept/object-initializers/.docs/hints.md @@ -1,6 +1,6 @@ ## General -- [object initializer][object-initializers] documentation describes how to use initialzers. +- [object initializer][object-initializers] documentation describes how to use initializers. - [collection initializer][collection-initializers] documentation gives a preview of how initializers can be used with collections like dictionaries and lists. ## 1. Store the system admin's details hard-coded in the system and make it available to callers. diff --git a/exercises/concept/operator-overloading/.docs/introduction.md b/exercises/concept/operator-overloading/.docs/introduction.md index daf28dc8cf..9c72dea800 100644 --- a/exercises/concept/operator-overloading/.docs/introduction.md +++ b/exercises/concept/operator-overloading/.docs/introduction.md @@ -3,7 +3,7 @@ The principal arithmetic and comparison operators can be adapted for use by your Most operators have the form: ```csharp -static operaator (); +static operator (); ``` Cast operators have the form: diff --git a/exercises/concept/properties/.docs/introduction.md b/exercises/concept/properties/.docs/introduction.md index f81e97a68d..1405dddcca 100644 --- a/exercises/concept/properties/.docs/introduction.md +++ b/exercises/concept/properties/.docs/introduction.md @@ -35,4 +35,4 @@ public int MyProperty public int MyProperty { get; private set; } = 42; ``` -Initialisation is optional. +Initialization is optional. diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/properties/.meta/design.md index 5e6e59b784..ae4dc986bc 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/properties/.meta/design.md @@ -13,7 +13,7 @@ Properties are covered early in the C# track as their purpose and power can be s - expression bodied properties, get accessors and set accessors (covered by expression-bodied members) - properties on interfaces (covered by Interfaces) -- properties/absract properties on abstract classes (covered by Inheritance) +- properties/abstract properties on abstract classes (covered by Inheritance) - use of the `readonly` keyword with properties (covered by Immutability) - static properties (covered by Statics) - indexers (covered by Indexers) diff --git a/exercises/concept/regular-expressions/.docs/instructions.md b/exercises/concept/regular-expressions/.docs/instructions.md index fa280fa9fb..83d9285907 100644 --- a/exercises/concept/regular-expressions/.docs/instructions.md +++ b/exercises/concept/regular-expressions/.docs/instructions.md @@ -1,6 +1,6 @@ This exercise addresses the parsing of log files. -After a recent security review you have been asked to clean up the organisation's archived log files. +After a recent security review you have been asked to clean up the organization's archived log files. All strings passed to the methods are guaranteed to be non-null and leading and without trailing spaces. @@ -74,7 +74,7 @@ Just remove the end of line string. Do not attempt to adjust the whitespaces. ```csharp var lp = new LogParser(); -lp.RemoveEndOfLineText("[INF] end-of-lline23033 Network Falure end-of-line27"); +lp.RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27"); // => "[INF] Network Failure " ``` @@ -93,7 +93,7 @@ Lines not containing an offending password should be returned prefixed with "--- ```csharp var lp = new LogParser(); lp.ListLinesWithPasswords(new string[] {"my passwordsecret is great"}); -// => "passwordsecre: my passwordsecret is great" +// => "passwordsecret: my passwordsecret is great" lp.ListLinesWithPasswords(new string[] {"my password secret"}); // => {"--------: my password secret"} diff --git a/exercises/concept/resource-cleanup/.docs/instructions.md b/exercises/concept/resource-cleanup/.docs/instructions.md index e088b6fa79..e6581a9fb1 100644 --- a/exercises/concept/resource-cleanup/.docs/instructions.md +++ b/exercises/concept/resource-cleanup/.docs/instructions.md @@ -9,9 +9,9 @@ Note that, internally, the database transitions through a number of state: Close The database has the following instance methods: - `Database.BeginTransaction()` starts a transaction on the database. If this is called when the database is not in a `Closed` state then an exception is thrown. If successful the internal state of the database will change to `TransactionStarted`. -- `Database.Write(string data)` writes data to the database within the transaction. If it receives bad data an exception will be thrown. An attempt to call this method without `BeginTransction()` having been called will cause an exception to be thrown. If successful the internal state of the database will change to `DataWritten`. +- `Database.Write(string data)` writes data to the database within the transaction. If it receives bad data an exception will be thrown. An attempt to call this method without `BeginTransaction()` having been called will cause an exception to be thrown. If successful the internal state of the database will change to `DataWritten`. - `Database.Commit()` commits the transaction to the database. It may throw an exception if it can't close the transaction of if `Database.BeginTransaction()` had not been called. -- A call to`Databse.Dispose()` will clean up the database if an exception is thrown during a transaction. This will change the state of the database to `Closed`. +- A call to`Database.Dispose()` will clean up the database if an exception is thrown during a transaction. This will change the state of the database to `Closed`. ## 1. Begin a transaction diff --git a/exercises/concept/resource-cleanup/.meta/design.md b/exercises/concept/resource-cleanup/.meta/design.md index 9a552e0605..787d008f21 100644 --- a/exercises/concept/resource-cleanup/.meta/design.md +++ b/exercises/concept/resource-cleanup/.meta/design.md @@ -10,7 +10,7 @@ ## Concepts -- `resource-cleanup`: Know how to clean up resources with `IDisposable` in C# and .NET. Understand the difference between managedd and unmanaged resources and the role of `IDisposable`. +- `resource-cleanup`: Know how to clean up resources with `IDisposable` in C# and .NET. Understand the difference between managed and unmanaged resources and the role of `IDisposable`. ## Prerequisites diff --git a/exercises/concept/resource-lifetime/.docs/introduction.md b/exercises/concept/resource-lifetime/.docs/introduction.md index 77a8122259..ee0bef510d 100644 --- a/exercises/concept/resource-lifetime/.docs/introduction.md +++ b/exercises/concept/resource-lifetime/.docs/introduction.md @@ -16,7 +16,7 @@ For the pattern to work the variable in the using statement must be a reference C# 8 introduces a refinement to the pattern. A using statement can placed at the beginning of a block. ```csharp -using var drawingResource = some_provided_or_newed_object; +using var drawingResource = some_provided_or_new_object; try { drawingResource.DrawSomething(); diff --git a/exercises/concept/time/.docs/instructions.md b/exercises/concept/time/.docs/instructions.md index f19b5b5778..43e1c02b5c 100644 --- a/exercises/concept/time/.docs/instructions.md +++ b/exercises/concept/time/.docs/instructions.md @@ -28,7 +28,7 @@ On Windows, they are: - London - GMT Standard Time - Paris - W. Europe Standard Time -Implement the static `Appointment.Shedule()` overload which takes a location and time string and returns the UTC time of the appointment. +Implement the static `Appointment.Schedule()` overload which takes a location and time string and returns the UTC time of the appointment. The implementation of `Schedule()` will need to allow the code, once built, to be run on Linux, Windows and Mac. This is the first exercise where you need to be concerned about the operating system. It will be necessary to have separate code paths to accommodate the difference in the time zone ids as described above. diff --git a/exercises/concept/tuples/.docs/introduction.md b/exercises/concept/tuples/.docs/introduction.md index fa89e2d77d..88510ef0c5 100644 --- a/exercises/concept/tuples/.docs/introduction.md +++ b/exercises/concept/tuples/.docs/introduction.md @@ -7,7 +7,7 @@ within a set of parentheses. ```csharp string boast = "All you need to know"; bool success = !string.IsNullOrWhiteSpace(boast); -(bool, int, string) tripple = (success, 42, boast); +(bool, int, string) triple = (success, 42, boast); ``` A tuple can be used in assignment and initialization operations, as a return value or a method argument. @@ -42,10 +42,10 @@ Field names `Item1` etc. do not make for readable code. The code below shows // name items in declaration (bool success, string message) results = (true, "well done!"); bool mySuccess = results.success; -string myMessaage = results.message; +string myMessage = results.message; // name items in creating expression var results2 = (success: true, message: "well done!"); bool mySuccess2 = results2.success; -string myMessaage2 = results2.message; +string myMessage2 = results2.message; ``` From ce99c2594fa2796eeb0189bc1ff6aba23547f6bc Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Tue, 27 Oct 2020 13:52:56 +0100 Subject: [PATCH 253/327] floating-point-numbers - replace about.md file with concept files * Pre-populate do-while-loops concept's about.md file from after.md file * Pre-populate do-while-loops concept's links.json file from after.md file * Pre-populate floating-point-numbers concept's about.md file from after.md file * Pre-populate floating-point-numbers concept's links.json file from after.md file * Pre-populate while-loops concept's about.md file from after.md file * Pre-populate while-loops concept's links.json file from after.md file * floating-point-numbers - Remove after.md document * Update about.md * Update links.json * Update about.md * Update about.md * Update links.json fixing broken link when after.md files removed * Update concept-exercises.md * Update generic-how-to-implement-a-concept-exercise.md Co-authored-by: Mike May --- concepts/do-while-loops/about.md | 16 ++++++- concepts/floating-point-numbers/about.md | 21 ++++++++- concepts/floating-point-numbers/links.json | 27 ++++++++++- concepts/while-loops/about.md | 12 ++++- .../floating-point-numbers/.docs/after.md | 47 ------------------- 5 files changed, 72 insertions(+), 51 deletions(-) delete mode 100644 exercises/concept/floating-point-numbers/.docs/after.md diff --git a/concepts/do-while-loops/about.md b/concepts/do-while-loops/about.md index 0241010b57..1a2d5d8f54 100644 --- a/concepts/do-while-loops/about.md +++ b/concepts/do-while-loops/about.md @@ -1 +1,15 @@ -TODO: add information on do-while-loops concept +TODO: clarify context for do-while loop +A closely related construct is the `do` loop: + +```csharp +int x = 0; + +do +{ + x = GetX(); + // do something with x +} +while (x != 0); +``` + +This is used less frequently than a `while` loop but in some cases results in more natural looking code. diff --git a/concepts/floating-point-numbers/about.md b/concepts/floating-point-numbers/about.md index 4b9cdcc49c..36b02423b0 100644 --- a/concepts/floating-point-numbers/about.md +++ b/concepts/floating-point-numbers/about.md @@ -1 +1,20 @@ -TODO: add information on floating-point-numbers concept +There are three floating-point types in C#: `double`, `float` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is written as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`. + +Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. + +Some conversions between floating point types are [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but others are [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. + +```csharp +decimal account = 125m * (decimal)1.2f; +``` + +Always be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. + +You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. + +[docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions +[docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions +[docs-microsoft.com-characteristics-of-the-floating-point-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types +[docs.microsoft.com_precision-in-comparisons]: https://docs.microsoft.com/en-us/dotnet/api/system.double.equals#precision-in-comparisons +[0.30000000000000004.com]: https://0.30000000000000004.com/ +[evanw.github.io-float-toy]: https://evanw.github.io/float-toy/ diff --git a/concepts/floating-point-numbers/links.json b/concepts/floating-point-numbers/links.json index fe51488c70..1ca67a03a3 100644 --- a/concepts/floating-point-numbers/links.json +++ b/concepts/floating-point-numbers/links.json @@ -1 +1,26 @@ -[] +[ + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types", + "description": "docs-microsoft.com-characteristics-of-the-floating-point-types" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions", + "description": "docs-microsoft.com-implicit-numeric-conversion" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions", + "description": "docs-microsoft.com-explicit-numeric-conversion" + }, + { + "url": "https://docs.microsoft.com/en-us/dotnet/api/system.double.equals#precision-in-comparisons", + "description": "docs.microsoft.com_precision-in-comparisons" + }, + { + "url": "https://0.30000000000000004.com/", + "description": "0.30000000000000004.com" + }, + { + "url": "https://evanw.github.io/float-toy/", + "description": "evanw.github.io-float-toy" + } +] diff --git a/concepts/while-loops/about.md b/concepts/while-loops/about.md index a9cd4eb710..de700d6af4 100644 --- a/concepts/while-loops/about.md +++ b/concepts/while-loops/about.md @@ -1 +1,11 @@ -TODO: add information on while-loops concept +To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `false`. + +```csharp +int x = 23; + +while (x > 10) +{ + // Execute logic if x > 10 + x = x - 1; +} +``` diff --git a/exercises/concept/floating-point-numbers/.docs/after.md b/exercises/concept/floating-point-numbers/.docs/after.md deleted file mode 100644 index 6c87e10f44..0000000000 --- a/exercises/concept/floating-point-numbers/.docs/after.md +++ /dev/null @@ -1,47 +0,0 @@ -There are three floating-point types in C#: `double`, `float` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is written as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`. - -Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types]. - -Some conversions between floating point types are [automatic (implicit)][docs-microsoft.com-implicit-numeric-conversion], but others are [manual (explicit)][docs-microsoft.com-explicit-numeric-conversion]. - -```csharp -decimal account = 125m * (decimal)1.2f; -``` - -Always be careful when checking the values of floating-point types for equality, as values that can appear to represent the same value could actually be different. See [this article][docs.microsoft.com_precision-in-comparisons] for more information. - -You can find a short introduction to floating-point numbers at [0.30000000000000004.com][0.30000000000000004.com]. The [Float Toy page][evanw.github.io-float-toy] has a nice, graphical explanation how a floating-point numbers' bits are converted to an actual floating-point value. - -To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `false`. - -```csharp -int x = 23; - -while (x > 10) -{ - // Execute logic if x > 10 - x = x - 1; -} -``` - -A closely related construct is the `do` loop: - -```csharp -int x = 0; - -do -{ - x = GetX(); - // do something with x -} -while (x != 0); -``` - -This is used less frequently than a `while` loop but in some cases results in more natural looking code. - -[docs-microsoft.com-explicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#explicit-numeric-conversions -[docs-microsoft.com-implicit-numeric-conversion]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/numeric-conversions#implicit-numeric-conversions -[docs-microsoft.com-characteristics-of-the-floating-point-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types#characteristics-of-the-floating-point-types -[docs.microsoft.com_precision-in-comparisons]: https://docs.microsoft.com/en-us/dotnet/api/system.double.equals#precision-in-comparisons -[0.30000000000000004.com]: https://0.30000000000000004.com/ -[evanw.github.io-float-toy]: https://evanw.github.io/float-toy/ From 0968bd3aec5246c667435a6a510bde16ec1a4c71 Mon Sep 17 00:00:00 2001 From: "Ashley E. Stallings" Date: Thu, 29 Oct 2020 08:03:09 -0500 Subject: [PATCH 254/327] Fix Struct Tests to build out of the box. * Used reflection to invoke plot constructor or throw error if not found. This allows the code to build out of the box instead of having build errors * fix white space issue for build pipeline * fix whitespace issues for build pipeline * fix whitespace issues for build pipeline * fix white space issue for build pipeline * Fix whitespace for build pipeline * Update languages/exercises/concept/structs/StructsTests.cs Co-authored-by: Mike May Co-authored-by: Mike May --- exercises/concept/structs/StructsTests.cs | 41 ++++++++++++++++------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/exercises/concept/structs/StructsTests.cs b/exercises/concept/structs/StructsTests.cs index 94d2067c53..08e43e399a 100644 --- a/exercises/concept/structs/StructsTests.cs +++ b/exercises/concept/structs/StructsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using Xunit; public class StructsTests @@ -7,8 +8,8 @@ public class StructsTests public void IsClaimed_yes() { var ch = new ClaimsHandler(); - ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); - var claimed = ch.IsClaimStaked(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + ch.StakeClaim(CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); + var claimed = ch.IsClaimStaked(CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); Assert.True(claimed); } @@ -16,8 +17,8 @@ public void IsClaimed_yes() public void IsClaimed_no() { var ch = new ClaimsHandler(); - ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); - var claimed = ch.IsClaimStaked(new Plot(new Coord(1,0), new Coord(2,1), new Coord(1,2), new Coord(2,2))); + ch.StakeClaim(CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); + var claimed = ch.IsClaimStaked(CreatePlot(new Coord(1, 0), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); Assert.False(claimed); } @@ -25,9 +26,9 @@ public void IsClaimed_no() public void IsLastClaim_yes() { var ch = new ClaimsHandler(); - ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); - ch.StakeClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); - var lastClaim = ch.IsLastClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + ch.StakeClaim(CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); + ch.StakeClaim(CreatePlot(new Coord(10, 1), new Coord(20, 1), new Coord(10, 2), new Coord(20, 2))); + var lastClaim = ch.IsLastClaim(CreatePlot(new Coord(10, 1), new Coord(20, 1), new Coord(10, 2), new Coord(20, 2))); Assert.True(lastClaim); } @@ -35,9 +36,9 @@ public void IsLastClaim_yes() public void IsLastClaim_no() { var ch = new ClaimsHandler(); - ch.StakeClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); - ch.StakeClaim(new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2))); - var lastClaim = ch.IsLastClaim(new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2))); + ch.StakeClaim(CreatePlot(new Coord(10, 1), new Coord(20, 1), new Coord(10, 2), new Coord(20, 2))); + ch.StakeClaim(CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2))); + var lastClaim = ch.IsLastClaim(CreatePlot(new Coord(10, 1), new Coord(20, 1), new Coord(10, 2), new Coord(20, 2))); Assert.False(lastClaim); } @@ -45,10 +46,26 @@ public void IsLastClaim_no() public void GetLongestSide() { var ch = new ClaimsHandler(); - var longer = new Plot(new Coord(10,1), new Coord(20,1), new Coord(10,2), new Coord(20,2)); - var shorter = new Plot(new Coord(1,1), new Coord(2,1), new Coord(1,2), new Coord(2,2)); + var longer = CreatePlot(new Coord(10, 1), new Coord(20, 1), new Coord(10, 2), new Coord(20, 2)); + var shorter = CreatePlot(new Coord(1, 1), new Coord(2, 1), new Coord(1, 2), new Coord(2, 2)); ch.StakeClaim(longer); ch.StakeClaim(shorter); Assert.Equal(longer, ch.GetClaimWithLongestSide()); } + + private Plot CreatePlot(Coord coord1, Coord coord2, Coord coord3, Coord coord4) + { + Type plotType = typeof(Plot); + Type[] types = new Type[] { typeof(Coord), typeof(Coord), typeof(Coord), typeof(Coord) }; + ConstructorInfo constructorInfoObj = plotType.GetConstructor(types); + if (constructorInfoObj != null) + { + return (Plot)constructorInfoObj.Invoke(new object[] { coord1, coord2, coord3, coord4 }); + } + + else + { + throw new InvalidOperationException("You need to implement a constructor for the struct Plot. The constructor must take 4 co-ordinates. No such constructor can be found."); + } + } } From d98f45e54926a3044128dd70dbe893f6c041f8bb Mon Sep 17 00:00:00 2001 From: "Ashley E. Stallings" Date: Thu, 29 Oct 2020 08:05:05 -0500 Subject: [PATCH 255/327] strings - add concatenation to introduction * introduce string concatenation * Fix whitespace issue for build pipeline * Remove accidentally committed file --- exercises/concept/strings/.docs/introduction.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/strings/.docs/introduction.md index db955821ba..d7d72cd2ec 100644 --- a/exercises/concept/strings/.docs/introduction.md +++ b/exercises/concept/strings/.docs/introduction.md @@ -5,3 +5,19 @@ string fruit = "Apple"; ``` Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string. + +Multiple strings can be concatenated (added) together. The simplest way to achieve this is by using the `+` operator. + +```csharp +string name = "Jane"; +"Hello " + name + "!"; +// => "Hello Jane!" +``` + +For any string formatting more complex than simple concatenation, string interpolation is preferred. To use interpolation in a string, prefix it with the dollar (`$`) symbol. Then you can use curly braces (`{}`) to access any variables inside your string. + +```csharp +string name = "Jane"; +$"Hello {name}!"; +// => "Hello Jane!" +``` From ee44f3a0326aa82d84f925c40f078aff820588cc Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Sat, 31 Oct 2020 15:20:16 +0100 Subject: [PATCH 256/327] Add editor key to exercises --- exercises/concept/arrays/.meta/config.json | 6 +++++- exercises/concept/basics/.meta/config.json | 6 +++++- exercises/concept/booleans/.meta/config.json | 6 +++++- exercises/concept/casting/.meta/config.json | 6 +++++- exercises/concept/chars/.meta/config.json | 6 +++++- exercises/concept/classes/.meta/config.json | 6 +++++- exercises/concept/constants/.meta/config.json | 6 +++++- exercises/concept/constructors/.meta/config.json | 6 +++++- exercises/concept/datetimes/.meta/config.json | 6 +++++- exercises/concept/dictionaries/.meta/config.json | 6 +++++- exercises/concept/enums/.meta/config.json | 6 +++++- exercises/concept/equality/.meta/config.json | 6 +++++- exercises/concept/exceptions/.meta/config.json | 6 +++++- .../concept/expression-bodied-members/.meta/config.json | 6 +++++- exercises/concept/flag-enums/.meta/config.json | 6 +++++- exercises/concept/floating-point-numbers/.meta/config.json | 6 +++++- exercises/concept/inheritance/.meta/config.json | 6 +++++- exercises/concept/integral-numbers/.meta/config.json | 6 +++++- exercises/concept/interfaces/.meta/config.json | 6 +++++- exercises/concept/lists/.meta/config.json | 6 +++++- exercises/concept/method-overloading/.meta/config.json | 6 +++++- exercises/concept/namespaces/.meta/config.json | 6 +++++- exercises/concept/nested-types/.meta/config.json | 6 +++++- exercises/concept/nullability/.meta/config.json | 6 +++++- exercises/concept/numbers/.meta/config.json | 6 +++++- exercises/concept/object-initializers/.meta/config.json | 6 +++++- exercises/concept/operator-overloading/.meta/config.json | 6 +++++- exercises/concept/overflow/.meta/config.json | 6 +++++- exercises/concept/parameters/.meta/config.json | 6 +++++- exercises/concept/properties/.meta/config.json | 6 +++++- exercises/concept/randomness/.meta/config.json | 6 +++++- exercises/concept/regular-expressions/.meta/config.json | 6 +++++- exercises/concept/resource-cleanup/.meta/config.json | 6 +++++- exercises/concept/resource-lifetime/.meta/config.json | 6 +++++- exercises/concept/string-formatting/.meta/config.json | 6 +++++- exercises/concept/strings/.meta/config.json | 6 +++++- exercises/concept/structs/.meta/config.json | 6 +++++- exercises/concept/switch-statements/.meta/config.json | 6 +++++- exercises/concept/time/.meta/config.json | 6 +++++- exercises/concept/tuples/.meta/config.json | 6 +++++- exercises/concept/user-defined-exceptions/.meta/config.json | 6 +++++- 41 files changed, 205 insertions(+), 41 deletions(-) diff --git a/exercises/concept/arrays/.meta/config.json b/exercises/concept/arrays/.meta/config.json index 6d4e44d872..2603d89780 100644 --- a/exercises/concept/arrays/.meta/config.json +++ b/exercises/concept/arrays/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Arrays.cs"], + "test_files": ["ArraysTests.cs"] + } } diff --git a/exercises/concept/basics/.meta/config.json b/exercises/concept/basics/.meta/config.json index 55ee67b595..9f79d8afa1 100644 --- a/exercises/concept/basics/.meta/config.json +++ b/exercises/concept/basics/.meta/config.json @@ -5,5 +5,9 @@ "exercism_username": "ErikSchierboom" } ], - "forked_from": ["fsharp/basics"] + "forked_from": ["fsharp/basics"], + "editor": { + "solution_files": ["Basics.cs"], + "test_files": ["BasicsTests.cs"] + } } diff --git a/exercises/concept/booleans/.meta/config.json b/exercises/concept/booleans/.meta/config.json index 6ae20d183e..a4cf6475a6 100644 --- a/exercises/concept/booleans/.meta/config.json +++ b/exercises/concept/booleans/.meta/config.json @@ -5,5 +5,9 @@ "exercism_username": "ErikSchierboom" } ], - "forked_from": ["fsharp/booleans"] + "forked_from": ["fsharp/booleans"], + "editor": { + "solution_files": ["Booleans.cs"], + "test_files": ["BooleansTests.cs"] + } } diff --git a/exercises/concept/casting/.meta/config.json b/exercises/concept/casting/.meta/config.json index 9212d455d1..3aa646115b 100644 --- a/exercises/concept/casting/.meta/config.json +++ b/exercises/concept/casting/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Casting.cs"], + "test_files": ["CastingTests.cs"] + } } diff --git a/exercises/concept/chars/.meta/config.json b/exercises/concept/chars/.meta/config.json index 9212d455d1..cbac7359ea 100644 --- a/exercises/concept/chars/.meta/config.json +++ b/exercises/concept/chars/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Chars.cs"], + "test_files": ["CharsTests.cs"] + } } diff --git a/exercises/concept/classes/.meta/config.json b/exercises/concept/classes/.meta/config.json index 6d4e44d872..ae84c97d6c 100644 --- a/exercises/concept/classes/.meta/config.json +++ b/exercises/concept/classes/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Classes.cs"], + "test_files": ["ClassesTests.cs"] + } } diff --git a/exercises/concept/constants/.meta/config.json b/exercises/concept/constants/.meta/config.json index 9212d455d1..94cb362993 100644 --- a/exercises/concept/constants/.meta/config.json +++ b/exercises/concept/constants/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Constants.cs"], + "test_files": ["ConstantsTests.cs"] + } } diff --git a/exercises/concept/constructors/.meta/config.json b/exercises/concept/constructors/.meta/config.json index 6d4e44d872..cdcb776bf2 100644 --- a/exercises/concept/constructors/.meta/config.json +++ b/exercises/concept/constructors/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Constructors.cs"], + "test_files": ["ConstructorsTests.cs"] + } } diff --git a/exercises/concept/datetimes/.meta/config.json b/exercises/concept/datetimes/.meta/config.json index 6d4e44d872..c0cb68eee3 100644 --- a/exercises/concept/datetimes/.meta/config.json +++ b/exercises/concept/datetimes/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Datetimes.cs"], + "test_files": ["DatetimesTests.cs"] + } } diff --git a/exercises/concept/dictionaries/.meta/config.json b/exercises/concept/dictionaries/.meta/config.json index 9212d455d1..f9df5065c3 100644 --- a/exercises/concept/dictionaries/.meta/config.json +++ b/exercises/concept/dictionaries/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Dictionaries.cs"], + "test_files": ["DictionariesTests.cs"] + } } diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/enums/.meta/config.json index 6d4e44d872..79e96c6d37 100644 --- a/exercises/concept/enums/.meta/config.json +++ b/exercises/concept/enums/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Enums.cs"], + "test_files": ["EnumsTests.cs"] + } } diff --git a/exercises/concept/equality/.meta/config.json b/exercises/concept/equality/.meta/config.json index 9212d455d1..e5517796d9 100644 --- a/exercises/concept/equality/.meta/config.json +++ b/exercises/concept/equality/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Equality.cs"], + "test_files": ["EqualityTests.cs"] + } } diff --git a/exercises/concept/exceptions/.meta/config.json b/exercises/concept/exceptions/.meta/config.json index 37e972ec01..adefbb12b4 100644 --- a/exercises/concept/exceptions/.meta/config.json +++ b/exercises/concept/exceptions/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "archrisV", "exercism_username": "archrisV" } - ] + ], + "editor": { + "solution_files": ["Exceptions.cs"], + "test_files": ["ExceptionsTests.cs"] + } } diff --git a/exercises/concept/expression-bodied-members/.meta/config.json b/exercises/concept/expression-bodied-members/.meta/config.json index 9212d455d1..4410a13244 100644 --- a/exercises/concept/expression-bodied-members/.meta/config.json +++ b/exercises/concept/expression-bodied-members/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Expression-bodied-members.cs"], + "test_files": ["Expression-bodied-membersTests.cs"] + } } diff --git a/exercises/concept/flag-enums/.meta/config.json b/exercises/concept/flag-enums/.meta/config.json index 6d4e44d872..1c99825fe2 100644 --- a/exercises/concept/flag-enums/.meta/config.json +++ b/exercises/concept/flag-enums/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Flag-enums.cs"], + "test_files": ["Flag-enumsTests.cs"] + } } diff --git a/exercises/concept/floating-point-numbers/.meta/config.json b/exercises/concept/floating-point-numbers/.meta/config.json index 6d4e44d872..a93240e66e 100644 --- a/exercises/concept/floating-point-numbers/.meta/config.json +++ b/exercises/concept/floating-point-numbers/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Floating-point-numbers.cs"], + "test_files": ["Floating-point-numbersTests.cs"] + } } diff --git a/exercises/concept/inheritance/.meta/config.json b/exercises/concept/inheritance/.meta/config.json index 6d4e44d872..9b7896684e 100644 --- a/exercises/concept/inheritance/.meta/config.json +++ b/exercises/concept/inheritance/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Inheritance.cs"], + "test_files": ["InheritanceTests.cs"] + } } diff --git a/exercises/concept/integral-numbers/.meta/config.json b/exercises/concept/integral-numbers/.meta/config.json index 9212d455d1..cb561a5e51 100644 --- a/exercises/concept/integral-numbers/.meta/config.json +++ b/exercises/concept/integral-numbers/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Integral-numbers.cs"], + "test_files": ["Integral-numbersTests.cs"] + } } diff --git a/exercises/concept/interfaces/.meta/config.json b/exercises/concept/interfaces/.meta/config.json index b367d9cb3c..31177a4e7d 100644 --- a/exercises/concept/interfaces/.meta/config.json +++ b/exercises/concept/interfaces/.meta/config.json @@ -14,5 +14,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Interfaces.cs"], + "test_files": ["InterfacesTests.cs"] + } } diff --git a/exercises/concept/lists/.meta/config.json b/exercises/concept/lists/.meta/config.json index 87e49b7fcb..fa8143ecf7 100644 --- a/exercises/concept/lists/.meta/config.json +++ b/exercises/concept/lists/.meta/config.json @@ -11,5 +11,9 @@ "exercism_username": "mikedamay" } ], - "forked_from": ["fsharp/lists"] + "forked_from": ["fsharp/lists"], + "editor": { + "solution_files": ["Lists.cs"], + "test_files": ["ListsTests.cs"] + } } diff --git a/exercises/concept/method-overloading/.meta/config.json b/exercises/concept/method-overloading/.meta/config.json index 6d4e44d872..101e6ec79a 100644 --- a/exercises/concept/method-overloading/.meta/config.json +++ b/exercises/concept/method-overloading/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Method-overloading.cs"], + "test_files": ["Method-overloadingTests.cs"] + } } diff --git a/exercises/concept/namespaces/.meta/config.json b/exercises/concept/namespaces/.meta/config.json index 9212d455d1..070b277110 100644 --- a/exercises/concept/namespaces/.meta/config.json +++ b/exercises/concept/namespaces/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Namespaces.cs"], + "test_files": ["NamespacesTests.cs"] + } } diff --git a/exercises/concept/nested-types/.meta/config.json b/exercises/concept/nested-types/.meta/config.json index 9212d455d1..eefecd618c 100644 --- a/exercises/concept/nested-types/.meta/config.json +++ b/exercises/concept/nested-types/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Nested-types.cs"], + "test_files": ["Nested-typesTests.cs"] + } } diff --git a/exercises/concept/nullability/.meta/config.json b/exercises/concept/nullability/.meta/config.json index 1c6ef680dd..a8d827340c 100644 --- a/exercises/concept/nullability/.meta/config.json +++ b/exercises/concept/nullability/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "maurelio1234", "exercism_username": "maurelio1234" } - ] + ], + "editor": { + "solution_files": ["Nullability.cs"], + "test_files": ["NullabilityTests.cs"] + } } diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json index 6d4e44d872..116f250d56 100644 --- a/exercises/concept/numbers/.meta/config.json +++ b/exercises/concept/numbers/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Numbers.cs"], + "test_files": ["NumbersTests.cs"] + } } diff --git a/exercises/concept/object-initializers/.meta/config.json b/exercises/concept/object-initializers/.meta/config.json index 9212d455d1..d56705fb8d 100644 --- a/exercises/concept/object-initializers/.meta/config.json +++ b/exercises/concept/object-initializers/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Object-initializers.cs"], + "test_files": ["Object-initializersTests.cs"] + } } diff --git a/exercises/concept/operator-overloading/.meta/config.json b/exercises/concept/operator-overloading/.meta/config.json index 9212d455d1..f55450964f 100644 --- a/exercises/concept/operator-overloading/.meta/config.json +++ b/exercises/concept/operator-overloading/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Operator-overloading.cs"], + "test_files": ["Operator-overloadingTests.cs"] + } } diff --git a/exercises/concept/overflow/.meta/config.json b/exercises/concept/overflow/.meta/config.json index 0816f0d60a..d938e77487 100644 --- a/exercises/concept/overflow/.meta/config.json +++ b/exercises/concept/overflow/.meta/config.json @@ -22,5 +22,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Overflow.cs"], + "test_files": ["OverflowTests.cs"] + } } diff --git a/exercises/concept/parameters/.meta/config.json b/exercises/concept/parameters/.meta/config.json index 9212d455d1..e1b9aab9ff 100644 --- a/exercises/concept/parameters/.meta/config.json +++ b/exercises/concept/parameters/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Parameters.cs"], + "test_files": ["ParametersTests.cs"] + } } diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json index 9212d455d1..38c3bcb7df 100644 --- a/exercises/concept/properties/.meta/config.json +++ b/exercises/concept/properties/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Properties.cs"], + "test_files": ["PropertiesTests.cs"] + } } diff --git a/exercises/concept/randomness/.meta/config.json b/exercises/concept/randomness/.meta/config.json index 9212d455d1..569be34f36 100644 --- a/exercises/concept/randomness/.meta/config.json +++ b/exercises/concept/randomness/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Randomness.cs"], + "test_files": ["RandomnessTests.cs"] + } } diff --git a/exercises/concept/regular-expressions/.meta/config.json b/exercises/concept/regular-expressions/.meta/config.json index 9212d455d1..517585e9b9 100644 --- a/exercises/concept/regular-expressions/.meta/config.json +++ b/exercises/concept/regular-expressions/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Regular-expressions.cs"], + "test_files": ["Regular-expressionsTests.cs"] + } } diff --git a/exercises/concept/resource-cleanup/.meta/config.json b/exercises/concept/resource-cleanup/.meta/config.json index 9212d455d1..2f8d1ac3f6 100644 --- a/exercises/concept/resource-cleanup/.meta/config.json +++ b/exercises/concept/resource-cleanup/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Resource-cleanup.cs"], + "test_files": ["Resource-cleanupTests.cs"] + } } diff --git a/exercises/concept/resource-lifetime/.meta/config.json b/exercises/concept/resource-lifetime/.meta/config.json index 9212d455d1..de0d690095 100644 --- a/exercises/concept/resource-lifetime/.meta/config.json +++ b/exercises/concept/resource-lifetime/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Resource-lifetime.cs"], + "test_files": ["Resource-lifetimeTests.cs"] + } } diff --git a/exercises/concept/string-formatting/.meta/config.json b/exercises/concept/string-formatting/.meta/config.json index 1fa3647d97..434fb5b0c0 100644 --- a/exercises/concept/string-formatting/.meta/config.json +++ b/exercises/concept/string-formatting/.meta/config.json @@ -11,5 +11,9 @@ "exercism_username": "mikedamay" } ], - "forked_from": ["elixir/strings"] + "forked_from": ["elixir/strings"], + "editor": { + "solution_files": ["String-formatting.cs"], + "test_files": ["String-formattingTests.cs"] + } } diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json index 6d4e44d872..c938b01f22 100644 --- a/exercises/concept/strings/.meta/config.json +++ b/exercises/concept/strings/.meta/config.json @@ -4,5 +4,9 @@ "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" } - ] + ], + "editor": { + "solution_files": ["Strings.cs"], + "test_files": ["StringsTests.cs"] + } } diff --git a/exercises/concept/structs/.meta/config.json b/exercises/concept/structs/.meta/config.json index 01d444e131..04e20562f4 100644 --- a/exercises/concept/structs/.meta/config.json +++ b/exercises/concept/structs/.meta/config.json @@ -18,5 +18,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Structs.cs"], + "test_files": ["StructsTests.cs"] + } } diff --git a/exercises/concept/switch-statements/.meta/config.json b/exercises/concept/switch-statements/.meta/config.json index c45cf94e8b..b5489477f6 100644 --- a/exercises/concept/switch-statements/.meta/config.json +++ b/exercises/concept/switch-statements/.meta/config.json @@ -14,5 +14,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Switch-statements.cs"], + "test_files": ["Switch-statementsTests.cs"] + } } diff --git a/exercises/concept/time/.meta/config.json b/exercises/concept/time/.meta/config.json index 9212d455d1..8584711c77 100644 --- a/exercises/concept/time/.meta/config.json +++ b/exercises/concept/time/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Time.cs"], + "test_files": ["TimeTests.cs"] + } } diff --git a/exercises/concept/tuples/.meta/config.json b/exercises/concept/tuples/.meta/config.json index 9212d455d1..e18ab16029 100644 --- a/exercises/concept/tuples/.meta/config.json +++ b/exercises/concept/tuples/.meta/config.json @@ -10,5 +10,9 @@ "github_username": "mikedamay", "exercism_username": "mikedamay" } - ] + ], + "editor": { + "solution_files": ["Tuples.cs"], + "test_files": ["TuplesTests.cs"] + } } diff --git a/exercises/concept/user-defined-exceptions/.meta/config.json b/exercises/concept/user-defined-exceptions/.meta/config.json index 8b317279aa..5b55090379 100644 --- a/exercises/concept/user-defined-exceptions/.meta/config.json +++ b/exercises/concept/user-defined-exceptions/.meta/config.json @@ -11,5 +11,9 @@ "exercism_username": "mikedamay" } ], - "forked_from": ["elixir/errors"] + "forked_from": ["elixir/errors"], + "editor": { + "solution_files": ["User-defined-exceptions.cs"], + "test_files": ["User-defined-exceptionsTests.cs"] + } } From 5ed2d4181e57257090772d15c6598cefcc117a3c Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 4 Nov 2020 10:11:20 +0100 Subject: [PATCH 257/327] Rename exercises Rename exercises --- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../AnnalynsInfiltration.cs} | 0 .../AnnalynsInfiltration.csproj} | 0 .../AnnalynsInfiltrationTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../attack-of-the-trolls/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../AttackOfTheTrolls.cs} | 0 .../AttackOfTheTrolls.csproj} | 0 .../AttackOfTheTrollsTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../authentication-system/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../AuthenticationSystem.cs} | 0 .../AuthenticationSystem.csproj} | 0 .../AuthenticationSystemTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../BeautySalonGoesGlobal.cs} | 0 .../BeautySalonGoesGlobal.csproj} | 0 .../BeautySalonGoesGlobalTests.cs} | 0 .../{arrays => bird-watcher}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{arrays => bird-watcher}/.meta/Example.cs | 0 .../{enums => bird-watcher}/.meta/config.json | 4 +- .../{arrays => bird-watcher}/.meta/design.md | 0 .../Arrays.cs => bird-watcher/BirdWatcher.cs} | 0 .../BirdWatcher.csproj} | 0 .../BirdWatcherTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../booking-up-for-beauty/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../BookingUpForBeauty.cs} | 0 .../BookingUpForBeauty.csproj} | 0 .../BookingUpForBeautyTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../building-telemetry/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../BuildingTelemetry.cs} | 0 .../BuildingTelemetry.csproj} | 0 .../BuildingTelemetryTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../CalculatorConundrum.cs} | 0 .../CalculatorConundrum.csproj} | 0 .../CalculatorConundrumTests.cs} | 0 .../{numbers => cars-assemble}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../CarsAssemble.cs} | 0 .../CarsAssemble.csproj} | 0 .../CarsAssembleTests.cs} | 0 .../{classes => elons-toys}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{classes => elons-toys}/.meta/Example.cs | 0 .../{arrays => elons-toys}/.meta/config.json | 4 +- .../{classes => elons-toys}/.meta/design.md | 0 .../Classes.cs => elons-toys/ElonsToys.cs} | 0 .../ElonsToys.csproj} | 0 .../ElonsToysTests.cs} | 0 .../.meta/config.json | 18 ---- .../{equality => faceid-2}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{equality => faceid-2}/.meta/Example.cs | 0 .../{chars => faceid-2}/.meta/config.json | 4 +- .../{equality => faceid-2}/.meta/design.md | 0 .../Equality.cs => faceid-2/Faceid2.cs} | 0 .../Faceid2.csproj} | 0 .../Faceid2Tests.cs} | 0 .../concept/flag-enums/.meta/config.json | 12 --- .../floating-point-numbers/.meta/config.json | 12 --- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../FootballMatchReports.cs} | 0 .../FootballMatchReports.csproj} | 0 .../FootballMatchReportsTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../HighSchoolSweethearts.cs} | 0 .../HighSchoolSweethearts.csproj} | 0 .../HighSchoolSweetheartsTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../HyperOptimizedTelemetry.cs} | 0 .../HyperOptimizedTelemetry.csproj} | 0 .../HyperOptimizedTelemetryTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../HyperiaForex.cs} | 0 .../HyperiaForex.csproj} | 0 .../HyperiaForexTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../HyperinflationHitsHyperia.cs} | 0 .../HyperinflationHitsHyperia.csproj} | 0 .../HyperinflationHitsHyperiaTests.cs} | 0 .../concept/inheritance/.meta/config.json | 12 --- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../InstrumentsOfTexas.cs} | 0 .../InstrumentsOfTexas.csproj} | 0 .../InstrumentsOfTexasTests.cs} | 0 .../integral-numbers/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../interest-is-interesting/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../InterestIsInteresting.cs} | 0 .../InterestIsInteresting.csproj} | 0 .../InterestIsInterestingTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../InternationalCallingConnoisseur.cs} | 0 .../InternationalCallingConnoisseur.csproj} | 0 .../InternationalCallingConnoisseurTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../LandGrabInSpace.cs} | 0 .../LandGrabInSpace.csproj} | 0 .../LandGrabInSpaceTests.cs} | 0 .../{strings => log-levels}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{strings => log-levels}/.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../{strings => log-levels}/.meta/design.md | 0 .../Strings.cs => log-levels/LogLevels.cs} | 0 .../LogLevels.csproj} | 0 .../LogLevelsTests.cs} | 0 .../{enums => logs-logs-logs}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../{enums => logs-logs-logs}/.meta/design.md | 0 .../LogsLogsLogs.cs} | 0 .../LogsLogsLogs.csproj} | 0 .../LogsLogsLogsTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../LuciansLusciousLasagna.cs} | 0 .../LuciansLusciousLasagna.csproj} | 0 .../LuciansLusciousLasagnaTests.cs} | 0 .../method-overloading/.meta/config.json | 12 --- .../concept/namespaces/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../concept/need-for-speed/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../NeedForSpeed.cs} | 0 .../NeedForSpeed.csproj} | 0 .../NeedForSpeedTests.cs} | 0 .../concept/nested-types/.meta/config.json | 18 ---- exercises/concept/numbers/.meta/config.json | 12 --- .../object-initializers/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../ObjectRelationalMapping.cs} | 0 .../ObjectRelationalMapping.csproj} | 0 .../ObjectRelationalMappingTests.cs} | 0 .../operator-overloading/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../OrmInOneGo.cs} | 0 .../OrmInOneGo.csproj} | 0 .../OrmInOneGoTests.cs} | 0 .../concept/parameters/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../parsing-log-files/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../ParsingLogFiles.cs} | 0 .../ParsingLogFiles.csproj} | 0 .../ParsingLogFilesTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../phone-number-analysis/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../PhoneNumberAnalysis.cs} | 0 .../PhoneNumberAnalysis.csproj} | 0 .../PhoneNumberAnalysisTests.cs} | 0 .../concept/properties/.meta/config.json | 18 ---- .../concept/randomness/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../RedVsBlueDarwinStyle.cs} | 0 .../RedVsBlueDarwinStyle.csproj} | 0 .../RedVsBlueDarwinStyleTests.cs} | 0 .../regular-expressions/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../remote-control-cleanup/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../RemoteControlCleanup.cs} | 0 .../RemoteControlCleanup.csproj} | 0 .../RemoteControlCleanupTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../RemoteControlCompetition.cs} | 0 .../RemoteControlCompetition.csproj} | 0 .../RemoteControlCompetitionTests.cs} | 0 .../resource-cleanup/.meta/config.json | 18 ---- .../resource-lifetime/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../RollTheDie.cs} | 0 .../RollTheDie.csproj} | 0 .../RollTheDieTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../SecureMunchesterUnited.cs} | 0 .../SecureMunchesterUnited.csproj} | 0 .../SecureMunchesterUnitedTests.cs} | 0 .../{chars => squeaky-clean}/.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../{chars => squeaky-clean}/.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../{chars => squeaky-clean}/.meta/design.md | 0 .../SqueakyClean.cs} | 0 .../SqueakyClean.csproj} | 0 .../SqueakyCleanTests.cs} | 0 exercises/concept/strings/.meta/config.json | 12 --- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../the-weather-in-deather/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../TheWeatherInDeather.cs} | 0 .../TheWeatherInDeather.csproj} | 0 .../TheWeatherInDeatherTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../TimFromMarketing.cs} | 0 .../TimFromMarketing.csproj} | 0 .../TimFromMarketingTests.cs} | 0 exercises/concept/time/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../.meta/config.json | 4 +- .../.meta/design.md | 0 .../TracksOnTracksOnTracks.cs} | 0 .../TracksOnTracksOnTracks.csproj} | 0 .../TracksOnTracksOnTracksTests.cs} | 0 exercises/concept/tuples/.meta/config.json | 18 ---- .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../weighing-machine/.meta/config.json | 18 ++++ .../.meta/design.md | 14 ++-- .../WeighingMachine.cs} | 0 .../WeighingMachine.csproj} | 0 .../WeighingMachineTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../why-cant-i-push-to-main/.meta/config.json | 18 ++++ .../.meta/design.md | 0 .../WhyCantIPushToMain.cs} | 0 .../WhyCantIPushToMain.csproj} | 0 .../WhyCantIPushToMainTests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../wizards-and-warriors-2/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../WizardsAndWarriors2.cs} | 0 .../WizardsAndWarriors2.csproj} | 0 .../WizardsAndWarriors2Tests.cs} | 0 .../.docs/hints.md | 0 .../.docs/instructions.md | 0 .../.docs/introduction.md | 0 .../.meta/Example.cs | 0 .../wizards-and-warriors/.meta/config.json | 12 +++ .../.meta/design.md | 0 .../WizardsAndWarriors.cs} | 0 .../WizardsAndWarriors.csproj} | 0 .../WizardsAndWarriorsTests.cs} | 0 reference/exercises.json | 82 +++++++++---------- reference/implementing-a-concept-exercise.md | 34 ++++---- 391 files changed, 431 insertions(+), 431 deletions(-) rename exercises/concept/{booleans => annalyns-infiltration}/.docs/hints.md (100%) rename exercises/concept/{booleans => annalyns-infiltration}/.docs/instructions.md (100%) rename exercises/concept/{booleans => annalyns-infiltration}/.docs/introduction.md (100%) rename exercises/concept/{booleans => annalyns-infiltration}/.meta/Example.cs (100%) rename exercises/concept/{booleans => annalyns-infiltration}/.meta/config.json (63%) rename exercises/concept/{booleans => annalyns-infiltration}/.meta/design.md (100%) rename exercises/concept/{booleans/Booleans.cs => annalyns-infiltration/AnnalynsInfiltration.cs} (100%) rename exercises/concept/{basics/Basics.csproj => annalyns-infiltration/AnnalynsInfiltration.csproj} (100%) rename exercises/concept/{booleans/BooleansTests.cs => annalyns-infiltration/AnnalynsInfiltrationTests.cs} (100%) rename exercises/concept/{flag-enums => attack-of-the-trolls}/.docs/hints.md (100%) rename exercises/concept/{flag-enums => attack-of-the-trolls}/.docs/instructions.md (100%) rename exercises/concept/{flag-enums => attack-of-the-trolls}/.docs/introduction.md (100%) rename exercises/concept/{flag-enums => attack-of-the-trolls}/.meta/Example.cs (100%) create mode 100644 exercises/concept/attack-of-the-trolls/.meta/config.json rename exercises/concept/{flag-enums => attack-of-the-trolls}/.meta/design.md (100%) rename exercises/concept/{flag-enums/FlagEnums.cs => attack-of-the-trolls/AttackOfTheTrolls.cs} (100%) rename exercises/concept/{booleans/Booleans.csproj => attack-of-the-trolls/AttackOfTheTrolls.csproj} (100%) rename exercises/concept/{flag-enums/FlagEnumsTests.cs => attack-of-the-trolls/AttackOfTheTrollsTests.cs} (100%) rename exercises/concept/{constants => authentication-system}/.docs/hints.md (100%) rename exercises/concept/{constants => authentication-system}/.docs/instructions.md (100%) rename exercises/concept/{constants => authentication-system}/.docs/introduction.md (100%) rename exercises/concept/{constants => authentication-system}/.meta/Example.cs (100%) create mode 100644 exercises/concept/authentication-system/.meta/config.json rename exercises/concept/{constants => authentication-system}/.meta/design.md (100%) rename exercises/concept/{constants/Constants.cs => authentication-system/AuthenticationSystem.cs} (100%) rename exercises/concept/{casting/Casting.csproj => authentication-system/AuthenticationSystem.csproj} (100%) rename exercises/concept/{constants/ConstantsTests.cs => authentication-system/AuthenticationSystemTests.cs} (100%) rename exercises/concept/{time => beauty-salon-goes-global}/.docs/hints.md (100%) rename exercises/concept/{time => beauty-salon-goes-global}/.docs/instructions.md (100%) rename exercises/concept/{time => beauty-salon-goes-global}/.docs/introduction.md (100%) rename exercises/concept/{time => beauty-salon-goes-global}/.meta/Example.cs (100%) create mode 100644 exercises/concept/beauty-salon-goes-global/.meta/config.json rename exercises/concept/{time => beauty-salon-goes-global}/.meta/design.md (100%) rename exercises/concept/{time/Time.cs => beauty-salon-goes-global/BeautySalonGoesGlobal.cs} (100%) rename exercises/concept/{chars/Chars.csproj => beauty-salon-goes-global/BeautySalonGoesGlobal.csproj} (100%) rename exercises/concept/{time/TimeTests.cs => beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs} (100%) rename exercises/concept/{arrays => bird-watcher}/.docs/hints.md (100%) rename exercises/concept/{arrays => bird-watcher}/.docs/instructions.md (100%) rename exercises/concept/{arrays => bird-watcher}/.docs/introduction.md (100%) rename exercises/concept/{arrays => bird-watcher}/.meta/Example.cs (100%) rename exercises/concept/{enums => bird-watcher}/.meta/config.json (62%) rename exercises/concept/{arrays => bird-watcher}/.meta/design.md (100%) rename exercises/concept/{arrays/Arrays.cs => bird-watcher/BirdWatcher.cs} (100%) rename exercises/concept/{arrays/Arrays.csproj => bird-watcher/BirdWatcher.csproj} (100%) rename exercises/concept/{arrays/ArraysTests.cs => bird-watcher/BirdWatcherTests.cs} (100%) rename exercises/concept/{datetimes => booking-up-for-beauty}/.docs/hints.md (100%) rename exercises/concept/{datetimes => booking-up-for-beauty}/.docs/instructions.md (100%) rename exercises/concept/{datetimes => booking-up-for-beauty}/.docs/introduction.md (100%) rename exercises/concept/{datetimes => booking-up-for-beauty}/.meta/Example.cs (100%) create mode 100644 exercises/concept/booking-up-for-beauty/.meta/config.json rename exercises/concept/{datetimes => booking-up-for-beauty}/.meta/design.md (100%) rename exercises/concept/{datetimes/DateTimes.cs => booking-up-for-beauty/BookingUpForBeauty.cs} (100%) rename exercises/concept/{classes/Classes.csproj => booking-up-for-beauty/BookingUpForBeauty.csproj} (100%) rename exercises/concept/{datetimes/DateTimesTests.cs => booking-up-for-beauty/BookingUpForBeautyTests.cs} (100%) rename exercises/concept/{parameters => building-telemetry}/.docs/hints.md (100%) rename exercises/concept/{parameters => building-telemetry}/.docs/instructions.md (100%) rename exercises/concept/{parameters => building-telemetry}/.docs/introduction.md (100%) rename exercises/concept/{parameters => building-telemetry}/.meta/Example.cs (100%) create mode 100644 exercises/concept/building-telemetry/.meta/config.json rename exercises/concept/{parameters => building-telemetry}/.meta/design.md (100%) rename exercises/concept/{parameters/Parameters.cs => building-telemetry/BuildingTelemetry.cs} (100%) rename exercises/concept/{constants/Constants.csproj => building-telemetry/BuildingTelemetry.csproj} (100%) rename exercises/concept/{parameters/ParametersTests.cs => building-telemetry/BuildingTelemetryTests.cs} (100%) rename exercises/concept/{exceptions => calculator-conundrum}/.docs/hints.md (100%) rename exercises/concept/{exceptions => calculator-conundrum}/.docs/instructions.md (100%) rename exercises/concept/{exceptions => calculator-conundrum}/.docs/introduction.md (100%) rename exercises/concept/{exceptions => calculator-conundrum}/.meta/Example.cs (100%) rename exercises/concept/{exceptions => calculator-conundrum}/.meta/config.json (57%) rename exercises/concept/{exceptions => calculator-conundrum}/.meta/design.md (100%) rename exercises/concept/{exceptions/Exceptions.cs => calculator-conundrum/CalculatorConundrum.cs} (100%) rename exercises/concept/{exceptions/Exceptions.csproj => calculator-conundrum/CalculatorConundrum.csproj} (100%) rename exercises/concept/{exceptions/ExceptionsTests.cs => calculator-conundrum/CalculatorConundrumTests.cs} (100%) rename exercises/concept/{numbers => cars-assemble}/.docs/hints.md (100%) rename exercises/concept/{numbers => cars-assemble}/.docs/instructions.md (100%) rename exercises/concept/{numbers => cars-assemble}/.docs/introduction.md (100%) rename exercises/concept/{numbers => cars-assemble}/.meta/Example.cs (100%) rename exercises/concept/{constructors => cars-assemble}/.meta/config.json (62%) rename exercises/concept/{numbers => cars-assemble}/.meta/design.md (100%) rename exercises/concept/{numbers/Numbers.cs => cars-assemble/CarsAssemble.cs} (100%) rename exercises/concept/{constructors/Constructors.csproj => cars-assemble/CarsAssemble.csproj} (100%) rename exercises/concept/{numbers/NumbersTests.cs => cars-assemble/CarsAssembleTests.cs} (100%) rename exercises/concept/{classes => elons-toys}/.docs/hints.md (100%) rename exercises/concept/{classes => elons-toys}/.docs/instructions.md (100%) rename exercises/concept/{classes => elons-toys}/.docs/introduction.md (100%) rename exercises/concept/{classes => elons-toys}/.meta/Example.cs (100%) rename exercises/concept/{arrays => elons-toys}/.meta/config.json (63%) rename exercises/concept/{classes => elons-toys}/.meta/design.md (100%) rename exercises/concept/{classes/Classes.cs => elons-toys/ElonsToys.cs} (100%) rename exercises/concept/{datetimes/DateTimes.csproj => elons-toys/ElonsToys.csproj} (100%) rename exercises/concept/{classes/ClassesTests.cs => elons-toys/ElonsToysTests.cs} (100%) delete mode 100644 exercises/concept/expression-bodied-members/.meta/config.json rename exercises/concept/{equality => faceid-2}/.docs/hints.md (100%) rename exercises/concept/{equality => faceid-2}/.docs/instructions.md (100%) rename exercises/concept/{equality => faceid-2}/.docs/introduction.md (100%) rename exercises/concept/{equality => faceid-2}/.meta/Example.cs (100%) rename exercises/concept/{chars => faceid-2}/.meta/config.json (77%) rename exercises/concept/{equality => faceid-2}/.meta/design.md (100%) rename exercises/concept/{equality/Equality.cs => faceid-2/Faceid2.cs} (100%) rename exercises/concept/{dictionaries/Dictionaries.csproj => faceid-2/Faceid2.csproj} (100%) rename exercises/concept/{equality/EqualityTests.cs => faceid-2/Faceid2Tests.cs} (100%) delete mode 100644 exercises/concept/flag-enums/.meta/config.json delete mode 100644 exercises/concept/floating-point-numbers/.meta/config.json rename exercises/concept/{switch-statements => football-match-reports}/.docs/hints.md (100%) rename exercises/concept/{switch-statements => football-match-reports}/.docs/instructions.md (100%) rename exercises/concept/{switch-statements => football-match-reports}/.docs/introduction.md (100%) rename exercises/concept/{switch-statements => football-match-reports}/.meta/Example.cs (100%) rename exercises/concept/{switch-statements => football-match-reports}/.meta/config.json (77%) rename exercises/concept/{switch-statements => football-match-reports}/.meta/design.md (100%) rename exercises/concept/{switch-statements/SwitchStatements.cs => football-match-reports/FootballMatchReports.cs} (100%) rename exercises/concept/{equality/Equality.csproj => football-match-reports/FootballMatchReports.csproj} (100%) rename exercises/concept/{switch-statements/SwitchStatementsTests.cs => football-match-reports/FootballMatchReportsTests.cs} (100%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.docs/hints.md (100%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.docs/instructions.md (100%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.docs/introduction.md (100%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.meta/Example.cs (100%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.meta/config.json (73%) rename exercises/concept/{string-formatting => high-school-sweethearts}/.meta/design.md (100%) rename exercises/concept/{string-formatting/StringFormatting.cs => high-school-sweethearts/HighSchoolSweethearts.cs} (100%) rename exercises/concept/{expression-bodied-members/ExpressionBodiedMembers.csproj => high-school-sweethearts/HighSchoolSweethearts.csproj} (100%) rename exercises/concept/{string-formatting/StringFormattingTests.cs => high-school-sweethearts/HighSchoolSweetheartsTests.cs} (100%) rename exercises/concept/{integral-numbers => hyper-optimized-telemetry}/.docs/hints.md (100%) rename exercises/concept/{integral-numbers => hyper-optimized-telemetry}/.docs/instructions.md (100%) rename exercises/concept/{integral-numbers => hyper-optimized-telemetry}/.docs/introduction.md (100%) rename exercises/concept/{integral-numbers => hyper-optimized-telemetry}/.meta/Example.cs (100%) create mode 100644 exercises/concept/hyper-optimized-telemetry/.meta/config.json rename exercises/concept/{integral-numbers => hyper-optimized-telemetry}/.meta/design.md (100%) rename exercises/concept/{integral-numbers/IntegralNumbers.cs => hyper-optimized-telemetry/HyperOptimizedTelemetry.cs} (100%) rename exercises/concept/{integral-numbers/IntegralNumbers.csproj => hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj} (100%) rename exercises/concept/{integral-numbers/IntegralNumbersTests.cs => hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs} (100%) rename exercises/concept/{operator-overloading => hyperia-forex}/.docs/hints.md (100%) rename exercises/concept/{operator-overloading => hyperia-forex}/.docs/instructions.md (100%) rename exercises/concept/{operator-overloading => hyperia-forex}/.docs/introduction.md (100%) rename exercises/concept/{operator-overloading => hyperia-forex}/.meta/Example.cs (100%) rename exercises/concept/{dictionaries => hyperia-forex}/.meta/config.json (74%) rename exercises/concept/{operator-overloading => hyperia-forex}/.meta/design.md (100%) rename exercises/concept/{operator-overloading/OperatorOverloading.cs => hyperia-forex/HyperiaForex.cs} (100%) rename exercises/concept/{interfaces/Interfaces.csproj => hyperia-forex/HyperiaForex.csproj} (100%) rename exercises/concept/{operator-overloading/OperatorOverloadingTests.cs => hyperia-forex/HyperiaForexTests.cs} (100%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.docs/hints.md (100%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.docs/instructions.md (100%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.docs/introduction.md (100%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.meta/Example.cs (100%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.meta/config.json (82%) rename exercises/concept/{overflow => hyperinflation-hits-hyperia}/.meta/design.md (100%) rename exercises/concept/{overflow/Overflow.cs => hyperinflation-hits-hyperia/HyperinflationHitsHyperia.cs} (100%) rename exercises/concept/{lists/Lists.csproj => hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj} (100%) rename exercises/concept/{overflow/OverflowTests.cs => hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs} (100%) delete mode 100644 exercises/concept/inheritance/.meta/config.json rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.docs/hints.md (100%) rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.docs/instructions.md (100%) rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.docs/introduction.md (100%) rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.meta/Example.cs (100%) rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.meta/config.json (72%) rename exercises/concept/{user-defined-exceptions => instruments-of-texas}/.meta/design.md (100%) rename exercises/concept/{user-defined-exceptions/UserDefinedExceptons.cs => instruments-of-texas/InstrumentsOfTexas.cs} (100%) rename exercises/concept/{namespaces/Namespaces.csproj => instruments-of-texas/InstrumentsOfTexas.csproj} (100%) rename exercises/concept/{user-defined-exceptions/UserDefinedExceptionsTests.cs => instruments-of-texas/InstrumentsOfTexasTests.cs} (100%) delete mode 100644 exercises/concept/integral-numbers/.meta/config.json rename exercises/concept/{floating-point-numbers => interest-is-interesting}/.docs/hints.md (100%) rename exercises/concept/{floating-point-numbers => interest-is-interesting}/.docs/instructions.md (100%) rename exercises/concept/{floating-point-numbers => interest-is-interesting}/.docs/introduction.md (100%) rename exercises/concept/{floating-point-numbers => interest-is-interesting}/.meta/Example.cs (100%) create mode 100644 exercises/concept/interest-is-interesting/.meta/config.json rename exercises/concept/{floating-point-numbers => interest-is-interesting}/.meta/design.md (100%) rename exercises/concept/{floating-point-numbers/FloatingPointNumbers.cs => interest-is-interesting/InterestIsInteresting.cs} (100%) rename exercises/concept/{enums/Enums.csproj => interest-is-interesting/InterestIsInteresting.csproj} (100%) rename exercises/concept/{floating-point-numbers/FloatingPointNumbersTests.cs => interest-is-interesting/InterestIsInterestingTests.cs} (100%) rename exercises/concept/{dictionaries => international-calling-connoisseur}/.docs/hints.md (100%) rename exercises/concept/{dictionaries => international-calling-connoisseur}/.docs/instructions.md (100%) rename exercises/concept/{dictionaries => international-calling-connoisseur}/.docs/introduction.md (100%) rename exercises/concept/{dictionaries => international-calling-connoisseur}/.meta/Example.cs (100%) create mode 100644 exercises/concept/international-calling-connoisseur/.meta/config.json rename exercises/concept/{dictionaries => international-calling-connoisseur}/.meta/design.md (100%) rename exercises/concept/{dictionaries/Dictionaries.cs => international-calling-connoisseur/InternationalCallingConnoisseur.cs} (100%) rename exercises/concept/{nested-types/NestedTypes.csproj => international-calling-connoisseur/InternationalCallingConnoisseur.csproj} (100%) rename exercises/concept/{dictionaries/DictionariesTests.cs => international-calling-connoisseur/InternationalCallingConnoisseurTests.cs} (100%) rename exercises/concept/{structs => land-grab-in-space}/.docs/hints.md (100%) rename exercises/concept/{structs => land-grab-in-space}/.docs/instructions.md (100%) rename exercises/concept/{structs => land-grab-in-space}/.docs/introduction.md (100%) rename exercises/concept/{structs => land-grab-in-space}/.meta/Example.cs (100%) rename exercises/concept/{structs => land-grab-in-space}/.meta/config.json (81%) rename exercises/concept/{structs => land-grab-in-space}/.meta/design.md (100%) rename exercises/concept/{structs/Structs.cs => land-grab-in-space/LandGrabInSpace.cs} (100%) rename exercises/concept/{object-initializers/ObjectInitialization.csproj => land-grab-in-space/LandGrabInSpace.csproj} (100%) rename exercises/concept/{structs/StructsTests.cs => land-grab-in-space/LandGrabInSpaceTests.cs} (100%) rename exercises/concept/{strings => log-levels}/.docs/hints.md (100%) rename exercises/concept/{strings => log-levels}/.docs/instructions.md (100%) rename exercises/concept/{strings => log-levels}/.docs/introduction.md (100%) rename exercises/concept/{strings => log-levels}/.meta/Example.cs (100%) rename exercises/concept/{datetimes => log-levels}/.meta/config.json (63%) rename exercises/concept/{strings => log-levels}/.meta/design.md (100%) rename exercises/concept/{strings/Strings.cs => log-levels/LogLevels.cs} (100%) rename exercises/concept/{flag-enums/FlagEnums.csproj => log-levels/LogLevels.csproj} (100%) rename exercises/concept/{strings/StringsTests.cs => log-levels/LogLevelsTests.cs} (100%) rename exercises/concept/{enums => logs-logs-logs}/.docs/hints.md (100%) rename exercises/concept/{enums => logs-logs-logs}/.docs/instructions.md (100%) rename exercises/concept/{enums => logs-logs-logs}/.docs/introduction.md (100%) rename exercises/concept/{enums => logs-logs-logs}/.meta/Example.cs (100%) rename exercises/concept/{classes => logs-logs-logs}/.meta/config.json (62%) rename exercises/concept/{enums => logs-logs-logs}/.meta/design.md (100%) rename exercises/concept/{enums/Enums.cs => logs-logs-logs/LogsLogsLogs.cs} (100%) rename exercises/concept/{floating-point-numbers/FloatingPointNumbers.csproj => logs-logs-logs/LogsLogsLogs.csproj} (100%) rename exercises/concept/{enums/EnumsTests.cs => logs-logs-logs/LogsLogsLogsTests.cs} (100%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.docs/hints.md (100%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.docs/instructions.md (100%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.docs/introduction.md (100%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.meta/Example.cs (100%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.meta/config.json (62%) rename exercises/concept/{basics => lucians-luscious-lasagna}/.meta/design.md (100%) rename exercises/concept/{basics/Basics.cs => lucians-luscious-lasagna/LuciansLusciousLasagna.cs} (100%) rename exercises/concept/{inheritance/Inheritance.csproj => lucians-luscious-lasagna/LuciansLusciousLasagna.csproj} (100%) rename exercises/concept/{basics/BasicsTests.cs => lucians-luscious-lasagna/LuciansLusciousLasagnaTests.cs} (100%) delete mode 100644 exercises/concept/method-overloading/.meta/config.json delete mode 100644 exercises/concept/namespaces/.meta/config.json rename exercises/concept/{constructors => need-for-speed}/.docs/hints.md (100%) rename exercises/concept/{constructors => need-for-speed}/.docs/instructions.md (100%) rename exercises/concept/{constructors => need-for-speed}/.docs/introduction.md (100%) rename exercises/concept/{constructors => need-for-speed}/.meta/Example.cs (100%) create mode 100644 exercises/concept/need-for-speed/.meta/config.json rename exercises/concept/{constructors => need-for-speed}/.meta/design.md (100%) rename exercises/concept/{constructors/Constructors.cs => need-for-speed/NeedForSpeed.cs} (100%) rename exercises/concept/{method-overloading/MethodOverloading.csproj => need-for-speed/NeedForSpeed.csproj} (100%) rename exercises/concept/{constructors/ConstructorsTests.cs => need-for-speed/NeedForSpeedTests.cs} (100%) delete mode 100644 exercises/concept/nested-types/.meta/config.json delete mode 100644 exercises/concept/numbers/.meta/config.json delete mode 100644 exercises/concept/object-initializers/.meta/config.json rename exercises/concept/{resource-cleanup => object-relational-mapping}/.docs/hints.md (100%) rename exercises/concept/{resource-cleanup => object-relational-mapping}/.docs/instructions.md (100%) rename exercises/concept/{resource-cleanup => object-relational-mapping}/.docs/introduction.md (100%) rename exercises/concept/{resource-cleanup => object-relational-mapping}/.meta/Example.cs (100%) create mode 100644 exercises/concept/object-relational-mapping/.meta/config.json rename exercises/concept/{resource-cleanup => object-relational-mapping}/.meta/design.md (100%) rename exercises/concept/{resource-cleanup/ResourceCleanup.cs => object-relational-mapping/ObjectRelationalMapping.cs} (100%) rename exercises/concept/{operator-overloading/OperatorOverloading.csproj => object-relational-mapping/ObjectRelationalMapping.csproj} (100%) rename exercises/concept/{resource-cleanup/ResourceCleanupTests.cs => object-relational-mapping/ObjectRelationalMappingTests.cs} (100%) delete mode 100644 exercises/concept/operator-overloading/.meta/config.json rename exercises/concept/{resource-lifetime => orm-in-one-go}/.docs/hints.md (100%) rename exercises/concept/{resource-lifetime => orm-in-one-go}/.docs/instructions.md (100%) rename exercises/concept/{resource-lifetime => orm-in-one-go}/.docs/introduction.md (100%) rename exercises/concept/{resource-lifetime => orm-in-one-go}/.meta/Example.cs (100%) rename exercises/concept/{constants => orm-in-one-go}/.meta/config.json (75%) rename exercises/concept/{resource-lifetime => orm-in-one-go}/.meta/design.md (100%) rename exercises/concept/{resource-lifetime/ResourceLifetime.cs => orm-in-one-go/OrmInOneGo.cs} (100%) rename exercises/concept/{overflow/Overflow.csproj => orm-in-one-go/OrmInOneGo.csproj} (100%) rename exercises/concept/{resource-lifetime/ResourceLifetimeTests.cs => orm-in-one-go/OrmInOneGoTests.cs} (100%) delete mode 100644 exercises/concept/parameters/.meta/config.json rename exercises/concept/{regular-expressions => parsing-log-files}/.docs/hints.md (100%) rename exercises/concept/{regular-expressions => parsing-log-files}/.docs/instructions.md (100%) rename exercises/concept/{regular-expressions => parsing-log-files}/.docs/introduction.md (100%) rename exercises/concept/{regular-expressions => parsing-log-files}/.meta/Example.cs (100%) create mode 100644 exercises/concept/parsing-log-files/.meta/config.json rename exercises/concept/{regular-expressions => parsing-log-files}/.meta/design.md (100%) rename exercises/concept/{regular-expressions/RegularExpressions.cs => parsing-log-files/ParsingLogFiles.cs} (100%) rename exercises/concept/{parameters/Parameters.csproj => parsing-log-files/ParsingLogFiles.csproj} (100%) rename exercises/concept/{regular-expressions/RegularExpressionsTests.cs => parsing-log-files/ParsingLogFilesTests.cs} (100%) rename exercises/concept/{tuples => phone-number-analysis}/.docs/hints.md (100%) rename exercises/concept/{tuples => phone-number-analysis}/.docs/instructions.md (100%) rename exercises/concept/{tuples => phone-number-analysis}/.docs/introduction.md (100%) rename exercises/concept/{tuples => phone-number-analysis}/.meta/Example.cs (100%) create mode 100644 exercises/concept/phone-number-analysis/.meta/config.json rename exercises/concept/{tuples => phone-number-analysis}/.meta/design.md (100%) rename exercises/concept/{tuples/Tuples.cs => phone-number-analysis/PhoneNumberAnalysis.cs} (100%) rename exercises/concept/{tuples/Tuples.csproj => phone-number-analysis/PhoneNumberAnalysis.csproj} (100%) rename exercises/concept/{tuples/TuplesTest.cs => phone-number-analysis/PhoneNumberAnalysisTests.cs} (100%) delete mode 100644 exercises/concept/properties/.meta/config.json delete mode 100644 exercises/concept/randomness/.meta/config.json rename exercises/concept/{namespaces => red-vs-blue-darwin-style}/.docs/hints.md (100%) rename exercises/concept/{namespaces => red-vs-blue-darwin-style}/.docs/instructions.md (100%) rename exercises/concept/{namespaces => red-vs-blue-darwin-style}/.docs/introduction.md (100%) rename exercises/concept/{namespaces => red-vs-blue-darwin-style}/.meta/Example.cs (100%) create mode 100644 exercises/concept/red-vs-blue-darwin-style/.meta/config.json rename exercises/concept/{namespaces => red-vs-blue-darwin-style}/.meta/design.md (100%) rename exercises/concept/{namespaces/Namespaces.cs => red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs} (100%) rename exercises/concept/{regular-expressions/RegularExpressions.csproj => red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj} (100%) rename exercises/concept/{namespaces/NamespacesTests.cs => red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs} (100%) delete mode 100644 exercises/concept/regular-expressions/.meta/config.json rename exercises/concept/{nested-types => remote-control-cleanup}/.docs/hints.md (100%) rename exercises/concept/{nested-types => remote-control-cleanup}/.docs/instructions.md (100%) rename exercises/concept/{nested-types => remote-control-cleanup}/.docs/introduction.md (100%) rename exercises/concept/{nested-types => remote-control-cleanup}/.meta/Example.cs (100%) create mode 100644 exercises/concept/remote-control-cleanup/.meta/config.json rename exercises/concept/{nested-types => remote-control-cleanup}/.meta/design.md (100%) rename exercises/concept/{nested-types/NestedTypes.cs => remote-control-cleanup/RemoteControlCleanup.cs} (100%) rename exercises/concept/{resource-cleanup/ResourceCleanup.csproj => remote-control-cleanup/RemoteControlCleanup.csproj} (100%) rename exercises/concept/{nested-types/NestedTypesTests.cs => remote-control-cleanup/RemoteControlCleanupTests.cs} (100%) rename exercises/concept/{interfaces => remote-control-competition}/.docs/hints.md (100%) rename exercises/concept/{interfaces => remote-control-competition}/.docs/instructions.md (100%) rename exercises/concept/{interfaces => remote-control-competition}/.docs/introduction.md (100%) rename exercises/concept/{interfaces => remote-control-competition}/.meta/Example.cs (100%) rename exercises/concept/{interfaces => remote-control-competition}/.meta/config.json (75%) rename exercises/concept/{interfaces => remote-control-competition}/.meta/design.md (100%) rename exercises/concept/{interfaces/Interfaces.cs => remote-control-competition/RemoteControlCompetition.cs} (100%) rename exercises/concept/{resource-lifetime/ResourceLifetime.csproj => remote-control-competition/RemoteControlCompetition.csproj} (100%) rename exercises/concept/{interfaces/InterfacesTests.cs => remote-control-competition/RemoteControlCompetitionTests.cs} (100%) delete mode 100644 exercises/concept/resource-cleanup/.meta/config.json delete mode 100644 exercises/concept/resource-lifetime/.meta/config.json rename exercises/concept/{randomness => roll-the-die}/.docs/hints.md (100%) rename exercises/concept/{randomness => roll-the-die}/.docs/instructions.md (100%) rename exercises/concept/{randomness => roll-the-die}/.docs/introduction.md (100%) rename exercises/concept/{randomness => roll-the-die}/.meta/Example.cs (100%) rename exercises/concept/{equality => roll-the-die}/.meta/config.json (75%) rename exercises/concept/{randomness => roll-the-die}/.meta/design.md (100%) rename exercises/concept/{randomness/Randomness.cs => roll-the-die/RollTheDie.cs} (100%) rename exercises/concept/{randomness/Randomness.csproj => roll-the-die/RollTheDie.csproj} (100%) rename exercises/concept/{randomness/RandomnessTests.cs => roll-the-die/RollTheDieTests.cs} (100%) rename exercises/concept/{casting => secure-munchester-united}/.docs/hints.md (100%) rename exercises/concept/{casting => secure-munchester-united}/.docs/instructions.md (100%) rename exercises/concept/{casting => secure-munchester-united}/.docs/introduction.md (100%) rename exercises/concept/{casting => secure-munchester-united}/.meta/Example.cs (100%) create mode 100644 exercises/concept/secure-munchester-united/.meta/config.json rename exercises/concept/{casting => secure-munchester-united}/.meta/design.md (100%) rename exercises/concept/{casting/Casting.cs => secure-munchester-united/SecureMunchesterUnited.cs} (100%) rename exercises/concept/{string-formatting/StringFormatting.csproj => secure-munchester-united/SecureMunchesterUnited.csproj} (100%) rename exercises/concept/{casting/CastingTests.cs => secure-munchester-united/SecureMunchesterUnitedTests.cs} (100%) rename exercises/concept/{chars => squeaky-clean}/.docs/hints.md (100%) rename exercises/concept/{chars => squeaky-clean}/.docs/instructions.md (100%) rename exercises/concept/{chars => squeaky-clean}/.docs/introduction.md (100%) rename exercises/concept/{chars => squeaky-clean}/.meta/Example.cs (100%) rename exercises/concept/{casting => squeaky-clean}/.meta/config.json (74%) rename exercises/concept/{chars => squeaky-clean}/.meta/design.md (100%) rename exercises/concept/{chars/Chars.cs => squeaky-clean/SqueakyClean.cs} (100%) rename exercises/concept/{structs/Structs.csproj => squeaky-clean/SqueakyClean.csproj} (100%) rename exercises/concept/{chars/CharsTests.cs => squeaky-clean/SqueakyCleanTests.cs} (100%) delete mode 100644 exercises/concept/strings/.meta/config.json rename exercises/concept/{expression-bodied-members => the-weather-in-deather}/.docs/hints.md (100%) rename exercises/concept/{expression-bodied-members => the-weather-in-deather}/.docs/instructions.md (100%) rename exercises/concept/{expression-bodied-members => the-weather-in-deather}/.docs/introduction.md (100%) rename exercises/concept/{expression-bodied-members => the-weather-in-deather}/.meta/Example.cs (100%) create mode 100644 exercises/concept/the-weather-in-deather/.meta/config.json rename exercises/concept/{expression-bodied-members => the-weather-in-deather}/.meta/design.md (100%) rename exercises/concept/{expression-bodied-members/ExpressionBodiedMembers.cs => the-weather-in-deather/TheWeatherInDeather.cs} (100%) rename exercises/concept/{switch-statements/SwitchStatements.csproj => the-weather-in-deather/TheWeatherInDeather.csproj} (100%) rename exercises/concept/{expression-bodied-members/ExpressionBodiedMembersTests.cs => the-weather-in-deather/TheWeatherInDeatherTests.cs} (100%) rename exercises/concept/{nullability => tim-from-marketing}/.docs/hints.md (100%) rename exercises/concept/{nullability => tim-from-marketing}/.docs/instructions.md (100%) rename exercises/concept/{nullability => tim-from-marketing}/.docs/introduction.md (100%) rename exercises/concept/{nullability => tim-from-marketing}/.meta/Example.cs (100%) rename exercises/concept/{nullability => tim-from-marketing}/.meta/config.json (59%) rename exercises/concept/{nullability => tim-from-marketing}/.meta/design.md (100%) rename exercises/concept/{nullability/Nullability.cs => tim-from-marketing/TimFromMarketing.cs} (100%) rename exercises/concept/{nullability/Nullability.csproj => tim-from-marketing/TimFromMarketing.csproj} (100%) rename exercises/concept/{nullability/NullabilityTests.cs => tim-from-marketing/TimFromMarketingTests.cs} (100%) delete mode 100644 exercises/concept/time/.meta/config.json rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.docs/hints.md (100%) rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.docs/instructions.md (100%) rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.docs/introduction.md (100%) rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.meta/Example.cs (100%) rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.meta/config.json (73%) rename exercises/concept/{lists => tracks-on-tracks-on-tracks}/.meta/design.md (100%) rename exercises/concept/{lists/Lists.cs => tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.cs} (100%) rename exercises/concept/{time/Time.csproj => tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj} (100%) rename exercises/concept/{lists/ListsTests.cs => tracks-on-tracks-on-tracks/TracksOnTracksOnTracksTests.cs} (100%) delete mode 100644 exercises/concept/tuples/.meta/config.json rename exercises/concept/{properties => weighing-machine}/.docs/hints.md (100%) rename exercises/concept/{properties => weighing-machine}/.docs/instructions.md (100%) rename exercises/concept/{properties => weighing-machine}/.docs/introduction.md (100%) rename exercises/concept/{properties => weighing-machine}/.meta/Example.cs (100%) create mode 100644 exercises/concept/weighing-machine/.meta/config.json rename exercises/concept/{properties => weighing-machine}/.meta/design.md (94%) rename exercises/concept/{properties/Properties.cs => weighing-machine/WeighingMachine.cs} (100%) rename exercises/concept/{properties/Properties.csproj => weighing-machine/WeighingMachine.csproj} (100%) rename exercises/concept/{properties/PropertiesTests.cs => weighing-machine/WeighingMachineTests.cs} (100%) rename exercises/concept/{object-initializers => why-cant-i-push-to-main}/.docs/hints.md (100%) rename exercises/concept/{object-initializers => why-cant-i-push-to-main}/.docs/instructions.md (100%) rename exercises/concept/{object-initializers => why-cant-i-push-to-main}/.docs/introduction.md (100%) rename exercises/concept/{object-initializers => why-cant-i-push-to-main}/.meta/Example.cs (100%) create mode 100644 exercises/concept/why-cant-i-push-to-main/.meta/config.json rename exercises/concept/{object-initializers => why-cant-i-push-to-main}/.meta/design.md (100%) rename exercises/concept/{object-initializers/ObjectInitialization.cs => why-cant-i-push-to-main/WhyCantIPushToMain.cs} (100%) rename exercises/concept/{user-defined-exceptions/UserDefinedExceptions.csproj => why-cant-i-push-to-main/WhyCantIPushToMain.csproj} (100%) rename exercises/concept/{object-initializers/ObjectInitializationTests.cs => why-cant-i-push-to-main/WhyCantIPushToMainTests.cs} (100%) rename exercises/concept/{method-overloading => wizards-and-warriors-2}/.docs/hints.md (100%) rename exercises/concept/{method-overloading => wizards-and-warriors-2}/.docs/instructions.md (100%) rename exercises/concept/{method-overloading => wizards-and-warriors-2}/.docs/introduction.md (100%) rename exercises/concept/{method-overloading => wizards-and-warriors-2}/.meta/Example.cs (100%) create mode 100644 exercises/concept/wizards-and-warriors-2/.meta/config.json rename exercises/concept/{method-overloading => wizards-and-warriors-2}/.meta/design.md (100%) rename exercises/concept/{method-overloading/MethodOverloading.cs => wizards-and-warriors-2/WizardsAndWarriors2.cs} (100%) rename exercises/concept/{numbers/Numbers.csproj => wizards-and-warriors-2/WizardsAndWarriors2.csproj} (100%) rename exercises/concept/{method-overloading/MethodOverloadingTests.cs => wizards-and-warriors-2/WizardsAndWarriors2Tests.cs} (100%) rename exercises/concept/{inheritance => wizards-and-warriors}/.docs/hints.md (100%) rename exercises/concept/{inheritance => wizards-and-warriors}/.docs/instructions.md (100%) rename exercises/concept/{inheritance => wizards-and-warriors}/.docs/introduction.md (100%) rename exercises/concept/{inheritance => wizards-and-warriors}/.meta/Example.cs (100%) create mode 100644 exercises/concept/wizards-and-warriors/.meta/config.json rename exercises/concept/{inheritance => wizards-and-warriors}/.meta/design.md (100%) rename exercises/concept/{inheritance/Inheritance.cs => wizards-and-warriors/WizardsAndWarriors.cs} (100%) rename exercises/concept/{strings/Strings.csproj => wizards-and-warriors/WizardsAndWarriors.csproj} (100%) rename exercises/concept/{inheritance/InheritanceTests.cs => wizards-and-warriors/WizardsAndWarriorsTests.cs} (100%) diff --git a/exercises/concept/booleans/.docs/hints.md b/exercises/concept/annalyns-infiltration/.docs/hints.md similarity index 100% rename from exercises/concept/booleans/.docs/hints.md rename to exercises/concept/annalyns-infiltration/.docs/hints.md diff --git a/exercises/concept/booleans/.docs/instructions.md b/exercises/concept/annalyns-infiltration/.docs/instructions.md similarity index 100% rename from exercises/concept/booleans/.docs/instructions.md rename to exercises/concept/annalyns-infiltration/.docs/instructions.md diff --git a/exercises/concept/booleans/.docs/introduction.md b/exercises/concept/annalyns-infiltration/.docs/introduction.md similarity index 100% rename from exercises/concept/booleans/.docs/introduction.md rename to exercises/concept/annalyns-infiltration/.docs/introduction.md diff --git a/exercises/concept/booleans/.meta/Example.cs b/exercises/concept/annalyns-infiltration/.meta/Example.cs similarity index 100% rename from exercises/concept/booleans/.meta/Example.cs rename to exercises/concept/annalyns-infiltration/.meta/Example.cs diff --git a/exercises/concept/booleans/.meta/config.json b/exercises/concept/annalyns-infiltration/.meta/config.json similarity index 63% rename from exercises/concept/booleans/.meta/config.json rename to exercises/concept/annalyns-infiltration/.meta/config.json index a4cf6475a6..1d189467e6 100644 --- a/exercises/concept/booleans/.meta/config.json +++ b/exercises/concept/annalyns-infiltration/.meta/config.json @@ -7,7 +7,7 @@ ], "forked_from": ["fsharp/booleans"], "editor": { - "solution_files": ["Booleans.cs"], - "test_files": ["BooleansTests.cs"] + "solution_files": ["AnnalynsInfiltration.cs"], + "test_files": ["AnnalynsInfiltrationTests.cs"] } } diff --git a/exercises/concept/booleans/.meta/design.md b/exercises/concept/annalyns-infiltration/.meta/design.md similarity index 100% rename from exercises/concept/booleans/.meta/design.md rename to exercises/concept/annalyns-infiltration/.meta/design.md diff --git a/exercises/concept/booleans/Booleans.cs b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.cs similarity index 100% rename from exercises/concept/booleans/Booleans.cs rename to exercises/concept/annalyns-infiltration/AnnalynsInfiltration.cs diff --git a/exercises/concept/basics/Basics.csproj b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj similarity index 100% rename from exercises/concept/basics/Basics.csproj rename to exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj diff --git a/exercises/concept/booleans/BooleansTests.cs b/exercises/concept/annalyns-infiltration/AnnalynsInfiltrationTests.cs similarity index 100% rename from exercises/concept/booleans/BooleansTests.cs rename to exercises/concept/annalyns-infiltration/AnnalynsInfiltrationTests.cs diff --git a/exercises/concept/flag-enums/.docs/hints.md b/exercises/concept/attack-of-the-trolls/.docs/hints.md similarity index 100% rename from exercises/concept/flag-enums/.docs/hints.md rename to exercises/concept/attack-of-the-trolls/.docs/hints.md diff --git a/exercises/concept/flag-enums/.docs/instructions.md b/exercises/concept/attack-of-the-trolls/.docs/instructions.md similarity index 100% rename from exercises/concept/flag-enums/.docs/instructions.md rename to exercises/concept/attack-of-the-trolls/.docs/instructions.md diff --git a/exercises/concept/flag-enums/.docs/introduction.md b/exercises/concept/attack-of-the-trolls/.docs/introduction.md similarity index 100% rename from exercises/concept/flag-enums/.docs/introduction.md rename to exercises/concept/attack-of-the-trolls/.docs/introduction.md diff --git a/exercises/concept/flag-enums/.meta/Example.cs b/exercises/concept/attack-of-the-trolls/.meta/Example.cs similarity index 100% rename from exercises/concept/flag-enums/.meta/Example.cs rename to exercises/concept/attack-of-the-trolls/.meta/Example.cs diff --git a/exercises/concept/attack-of-the-trolls/.meta/config.json b/exercises/concept/attack-of-the-trolls/.meta/config.json new file mode 100644 index 0000000000..0c0ed1f186 --- /dev/null +++ b/exercises/concept/attack-of-the-trolls/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["AttackOfTheTrolls.cs"], + "test_files": ["AttackOfTheTrollsTests.cs"] + } +} diff --git a/exercises/concept/flag-enums/.meta/design.md b/exercises/concept/attack-of-the-trolls/.meta/design.md similarity index 100% rename from exercises/concept/flag-enums/.meta/design.md rename to exercises/concept/attack-of-the-trolls/.meta/design.md diff --git a/exercises/concept/flag-enums/FlagEnums.cs b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.cs similarity index 100% rename from exercises/concept/flag-enums/FlagEnums.cs rename to exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.cs diff --git a/exercises/concept/booleans/Booleans.csproj b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj similarity index 100% rename from exercises/concept/booleans/Booleans.csproj rename to exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj diff --git a/exercises/concept/flag-enums/FlagEnumsTests.cs b/exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs similarity index 100% rename from exercises/concept/flag-enums/FlagEnumsTests.cs rename to exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs diff --git a/exercises/concept/constants/.docs/hints.md b/exercises/concept/authentication-system/.docs/hints.md similarity index 100% rename from exercises/concept/constants/.docs/hints.md rename to exercises/concept/authentication-system/.docs/hints.md diff --git a/exercises/concept/constants/.docs/instructions.md b/exercises/concept/authentication-system/.docs/instructions.md similarity index 100% rename from exercises/concept/constants/.docs/instructions.md rename to exercises/concept/authentication-system/.docs/instructions.md diff --git a/exercises/concept/constants/.docs/introduction.md b/exercises/concept/authentication-system/.docs/introduction.md similarity index 100% rename from exercises/concept/constants/.docs/introduction.md rename to exercises/concept/authentication-system/.docs/introduction.md diff --git a/exercises/concept/constants/.meta/Example.cs b/exercises/concept/authentication-system/.meta/Example.cs similarity index 100% rename from exercises/concept/constants/.meta/Example.cs rename to exercises/concept/authentication-system/.meta/Example.cs diff --git a/exercises/concept/authentication-system/.meta/config.json b/exercises/concept/authentication-system/.meta/config.json new file mode 100644 index 0000000000..1642f0967f --- /dev/null +++ b/exercises/concept/authentication-system/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["AuthenticationSystem.cs"], + "test_files": ["AuthenticationSystemTests.cs"] + } +} diff --git a/exercises/concept/constants/.meta/design.md b/exercises/concept/authentication-system/.meta/design.md similarity index 100% rename from exercises/concept/constants/.meta/design.md rename to exercises/concept/authentication-system/.meta/design.md diff --git a/exercises/concept/constants/Constants.cs b/exercises/concept/authentication-system/AuthenticationSystem.cs similarity index 100% rename from exercises/concept/constants/Constants.cs rename to exercises/concept/authentication-system/AuthenticationSystem.cs diff --git a/exercises/concept/casting/Casting.csproj b/exercises/concept/authentication-system/AuthenticationSystem.csproj similarity index 100% rename from exercises/concept/casting/Casting.csproj rename to exercises/concept/authentication-system/AuthenticationSystem.csproj diff --git a/exercises/concept/constants/ConstantsTests.cs b/exercises/concept/authentication-system/AuthenticationSystemTests.cs similarity index 100% rename from exercises/concept/constants/ConstantsTests.cs rename to exercises/concept/authentication-system/AuthenticationSystemTests.cs diff --git a/exercises/concept/time/.docs/hints.md b/exercises/concept/beauty-salon-goes-global/.docs/hints.md similarity index 100% rename from exercises/concept/time/.docs/hints.md rename to exercises/concept/beauty-salon-goes-global/.docs/hints.md diff --git a/exercises/concept/time/.docs/instructions.md b/exercises/concept/beauty-salon-goes-global/.docs/instructions.md similarity index 100% rename from exercises/concept/time/.docs/instructions.md rename to exercises/concept/beauty-salon-goes-global/.docs/instructions.md diff --git a/exercises/concept/time/.docs/introduction.md b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md similarity index 100% rename from exercises/concept/time/.docs/introduction.md rename to exercises/concept/beauty-salon-goes-global/.docs/introduction.md diff --git a/exercises/concept/time/.meta/Example.cs b/exercises/concept/beauty-salon-goes-global/.meta/Example.cs similarity index 100% rename from exercises/concept/time/.meta/Example.cs rename to exercises/concept/beauty-salon-goes-global/.meta/Example.cs diff --git a/exercises/concept/beauty-salon-goes-global/.meta/config.json b/exercises/concept/beauty-salon-goes-global/.meta/config.json new file mode 100644 index 0000000000..eb0e1887db --- /dev/null +++ b/exercises/concept/beauty-salon-goes-global/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["BeautySalonGoesGlobal.cs"], + "test_files": ["BeautySalonGoesGlobalTests.cs"] + } +} diff --git a/exercises/concept/time/.meta/design.md b/exercises/concept/beauty-salon-goes-global/.meta/design.md similarity index 100% rename from exercises/concept/time/.meta/design.md rename to exercises/concept/beauty-salon-goes-global/.meta/design.md diff --git a/exercises/concept/time/Time.cs b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.cs similarity index 100% rename from exercises/concept/time/Time.cs rename to exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.cs diff --git a/exercises/concept/chars/Chars.csproj b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj similarity index 100% rename from exercises/concept/chars/Chars.csproj rename to exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj diff --git a/exercises/concept/time/TimeTests.cs b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs similarity index 100% rename from exercises/concept/time/TimeTests.cs rename to exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs diff --git a/exercises/concept/arrays/.docs/hints.md b/exercises/concept/bird-watcher/.docs/hints.md similarity index 100% rename from exercises/concept/arrays/.docs/hints.md rename to exercises/concept/bird-watcher/.docs/hints.md diff --git a/exercises/concept/arrays/.docs/instructions.md b/exercises/concept/bird-watcher/.docs/instructions.md similarity index 100% rename from exercises/concept/arrays/.docs/instructions.md rename to exercises/concept/bird-watcher/.docs/instructions.md diff --git a/exercises/concept/arrays/.docs/introduction.md b/exercises/concept/bird-watcher/.docs/introduction.md similarity index 100% rename from exercises/concept/arrays/.docs/introduction.md rename to exercises/concept/bird-watcher/.docs/introduction.md diff --git a/exercises/concept/arrays/.meta/Example.cs b/exercises/concept/bird-watcher/.meta/Example.cs similarity index 100% rename from exercises/concept/arrays/.meta/Example.cs rename to exercises/concept/bird-watcher/.meta/Example.cs diff --git a/exercises/concept/enums/.meta/config.json b/exercises/concept/bird-watcher/.meta/config.json similarity index 62% rename from exercises/concept/enums/.meta/config.json rename to exercises/concept/bird-watcher/.meta/config.json index 79e96c6d37..83d1f35fef 100644 --- a/exercises/concept/enums/.meta/config.json +++ b/exercises/concept/bird-watcher/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Enums.cs"], - "test_files": ["EnumsTests.cs"] + "solution_files": ["BirdWatcher.cs"], + "test_files": ["BirdWatcherTests.cs"] } } diff --git a/exercises/concept/arrays/.meta/design.md b/exercises/concept/bird-watcher/.meta/design.md similarity index 100% rename from exercises/concept/arrays/.meta/design.md rename to exercises/concept/bird-watcher/.meta/design.md diff --git a/exercises/concept/arrays/Arrays.cs b/exercises/concept/bird-watcher/BirdWatcher.cs similarity index 100% rename from exercises/concept/arrays/Arrays.cs rename to exercises/concept/bird-watcher/BirdWatcher.cs diff --git a/exercises/concept/arrays/Arrays.csproj b/exercises/concept/bird-watcher/BirdWatcher.csproj similarity index 100% rename from exercises/concept/arrays/Arrays.csproj rename to exercises/concept/bird-watcher/BirdWatcher.csproj diff --git a/exercises/concept/arrays/ArraysTests.cs b/exercises/concept/bird-watcher/BirdWatcherTests.cs similarity index 100% rename from exercises/concept/arrays/ArraysTests.cs rename to exercises/concept/bird-watcher/BirdWatcherTests.cs diff --git a/exercises/concept/datetimes/.docs/hints.md b/exercises/concept/booking-up-for-beauty/.docs/hints.md similarity index 100% rename from exercises/concept/datetimes/.docs/hints.md rename to exercises/concept/booking-up-for-beauty/.docs/hints.md diff --git a/exercises/concept/datetimes/.docs/instructions.md b/exercises/concept/booking-up-for-beauty/.docs/instructions.md similarity index 100% rename from exercises/concept/datetimes/.docs/instructions.md rename to exercises/concept/booking-up-for-beauty/.docs/instructions.md diff --git a/exercises/concept/datetimes/.docs/introduction.md b/exercises/concept/booking-up-for-beauty/.docs/introduction.md similarity index 100% rename from exercises/concept/datetimes/.docs/introduction.md rename to exercises/concept/booking-up-for-beauty/.docs/introduction.md diff --git a/exercises/concept/datetimes/.meta/Example.cs b/exercises/concept/booking-up-for-beauty/.meta/Example.cs similarity index 100% rename from exercises/concept/datetimes/.meta/Example.cs rename to exercises/concept/booking-up-for-beauty/.meta/Example.cs diff --git a/exercises/concept/booking-up-for-beauty/.meta/config.json b/exercises/concept/booking-up-for-beauty/.meta/config.json new file mode 100644 index 0000000000..80aa03f7fd --- /dev/null +++ b/exercises/concept/booking-up-for-beauty/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["BookingUpForBeauty.cs"], + "test_files": ["BookingUpForBeautyTests.cs"] + } +} diff --git a/exercises/concept/datetimes/.meta/design.md b/exercises/concept/booking-up-for-beauty/.meta/design.md similarity index 100% rename from exercises/concept/datetimes/.meta/design.md rename to exercises/concept/booking-up-for-beauty/.meta/design.md diff --git a/exercises/concept/datetimes/DateTimes.cs b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.cs similarity index 100% rename from exercises/concept/datetimes/DateTimes.cs rename to exercises/concept/booking-up-for-beauty/BookingUpForBeauty.cs diff --git a/exercises/concept/classes/Classes.csproj b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj similarity index 100% rename from exercises/concept/classes/Classes.csproj rename to exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj diff --git a/exercises/concept/datetimes/DateTimesTests.cs b/exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs similarity index 100% rename from exercises/concept/datetimes/DateTimesTests.cs rename to exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs diff --git a/exercises/concept/parameters/.docs/hints.md b/exercises/concept/building-telemetry/.docs/hints.md similarity index 100% rename from exercises/concept/parameters/.docs/hints.md rename to exercises/concept/building-telemetry/.docs/hints.md diff --git a/exercises/concept/parameters/.docs/instructions.md b/exercises/concept/building-telemetry/.docs/instructions.md similarity index 100% rename from exercises/concept/parameters/.docs/instructions.md rename to exercises/concept/building-telemetry/.docs/instructions.md diff --git a/exercises/concept/parameters/.docs/introduction.md b/exercises/concept/building-telemetry/.docs/introduction.md similarity index 100% rename from exercises/concept/parameters/.docs/introduction.md rename to exercises/concept/building-telemetry/.docs/introduction.md diff --git a/exercises/concept/parameters/.meta/Example.cs b/exercises/concept/building-telemetry/.meta/Example.cs similarity index 100% rename from exercises/concept/parameters/.meta/Example.cs rename to exercises/concept/building-telemetry/.meta/Example.cs diff --git a/exercises/concept/building-telemetry/.meta/config.json b/exercises/concept/building-telemetry/.meta/config.json new file mode 100644 index 0000000000..3f09598013 --- /dev/null +++ b/exercises/concept/building-telemetry/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["BuildingTelemetry.cs"], + "test_files": ["BuildingTelemetryTests.cs"] + } +} diff --git a/exercises/concept/parameters/.meta/design.md b/exercises/concept/building-telemetry/.meta/design.md similarity index 100% rename from exercises/concept/parameters/.meta/design.md rename to exercises/concept/building-telemetry/.meta/design.md diff --git a/exercises/concept/parameters/Parameters.cs b/exercises/concept/building-telemetry/BuildingTelemetry.cs similarity index 100% rename from exercises/concept/parameters/Parameters.cs rename to exercises/concept/building-telemetry/BuildingTelemetry.cs diff --git a/exercises/concept/constants/Constants.csproj b/exercises/concept/building-telemetry/BuildingTelemetry.csproj similarity index 100% rename from exercises/concept/constants/Constants.csproj rename to exercises/concept/building-telemetry/BuildingTelemetry.csproj diff --git a/exercises/concept/parameters/ParametersTests.cs b/exercises/concept/building-telemetry/BuildingTelemetryTests.cs similarity index 100% rename from exercises/concept/parameters/ParametersTests.cs rename to exercises/concept/building-telemetry/BuildingTelemetryTests.cs diff --git a/exercises/concept/exceptions/.docs/hints.md b/exercises/concept/calculator-conundrum/.docs/hints.md similarity index 100% rename from exercises/concept/exceptions/.docs/hints.md rename to exercises/concept/calculator-conundrum/.docs/hints.md diff --git a/exercises/concept/exceptions/.docs/instructions.md b/exercises/concept/calculator-conundrum/.docs/instructions.md similarity index 100% rename from exercises/concept/exceptions/.docs/instructions.md rename to exercises/concept/calculator-conundrum/.docs/instructions.md diff --git a/exercises/concept/exceptions/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md similarity index 100% rename from exercises/concept/exceptions/.docs/introduction.md rename to exercises/concept/calculator-conundrum/.docs/introduction.md diff --git a/exercises/concept/exceptions/.meta/Example.cs b/exercises/concept/calculator-conundrum/.meta/Example.cs similarity index 100% rename from exercises/concept/exceptions/.meta/Example.cs rename to exercises/concept/calculator-conundrum/.meta/Example.cs diff --git a/exercises/concept/exceptions/.meta/config.json b/exercises/concept/calculator-conundrum/.meta/config.json similarity index 57% rename from exercises/concept/exceptions/.meta/config.json rename to exercises/concept/calculator-conundrum/.meta/config.json index adefbb12b4..6eafd7d765 100644 --- a/exercises/concept/exceptions/.meta/config.json +++ b/exercises/concept/calculator-conundrum/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Exceptions.cs"], - "test_files": ["ExceptionsTests.cs"] + "solution_files": ["CalculatorConundrum.cs"], + "test_files": ["CalculatorConundrumTests.cs"] } } diff --git a/exercises/concept/exceptions/.meta/design.md b/exercises/concept/calculator-conundrum/.meta/design.md similarity index 100% rename from exercises/concept/exceptions/.meta/design.md rename to exercises/concept/calculator-conundrum/.meta/design.md diff --git a/exercises/concept/exceptions/Exceptions.cs b/exercises/concept/calculator-conundrum/CalculatorConundrum.cs similarity index 100% rename from exercises/concept/exceptions/Exceptions.cs rename to exercises/concept/calculator-conundrum/CalculatorConundrum.cs diff --git a/exercises/concept/exceptions/Exceptions.csproj b/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj similarity index 100% rename from exercises/concept/exceptions/Exceptions.csproj rename to exercises/concept/calculator-conundrum/CalculatorConundrum.csproj diff --git a/exercises/concept/exceptions/ExceptionsTests.cs b/exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs similarity index 100% rename from exercises/concept/exceptions/ExceptionsTests.cs rename to exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs diff --git a/exercises/concept/numbers/.docs/hints.md b/exercises/concept/cars-assemble/.docs/hints.md similarity index 100% rename from exercises/concept/numbers/.docs/hints.md rename to exercises/concept/cars-assemble/.docs/hints.md diff --git a/exercises/concept/numbers/.docs/instructions.md b/exercises/concept/cars-assemble/.docs/instructions.md similarity index 100% rename from exercises/concept/numbers/.docs/instructions.md rename to exercises/concept/cars-assemble/.docs/instructions.md diff --git a/exercises/concept/numbers/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md similarity index 100% rename from exercises/concept/numbers/.docs/introduction.md rename to exercises/concept/cars-assemble/.docs/introduction.md diff --git a/exercises/concept/numbers/.meta/Example.cs b/exercises/concept/cars-assemble/.meta/Example.cs similarity index 100% rename from exercises/concept/numbers/.meta/Example.cs rename to exercises/concept/cars-assemble/.meta/Example.cs diff --git a/exercises/concept/constructors/.meta/config.json b/exercises/concept/cars-assemble/.meta/config.json similarity index 62% rename from exercises/concept/constructors/.meta/config.json rename to exercises/concept/cars-assemble/.meta/config.json index cdcb776bf2..2247d06564 100644 --- a/exercises/concept/constructors/.meta/config.json +++ b/exercises/concept/cars-assemble/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Constructors.cs"], - "test_files": ["ConstructorsTests.cs"] + "solution_files": ["CarsAssemble.cs"], + "test_files": ["CarsAssembleTests.cs"] } } diff --git a/exercises/concept/numbers/.meta/design.md b/exercises/concept/cars-assemble/.meta/design.md similarity index 100% rename from exercises/concept/numbers/.meta/design.md rename to exercises/concept/cars-assemble/.meta/design.md diff --git a/exercises/concept/numbers/Numbers.cs b/exercises/concept/cars-assemble/CarsAssemble.cs similarity index 100% rename from exercises/concept/numbers/Numbers.cs rename to exercises/concept/cars-assemble/CarsAssemble.cs diff --git a/exercises/concept/constructors/Constructors.csproj b/exercises/concept/cars-assemble/CarsAssemble.csproj similarity index 100% rename from exercises/concept/constructors/Constructors.csproj rename to exercises/concept/cars-assemble/CarsAssemble.csproj diff --git a/exercises/concept/numbers/NumbersTests.cs b/exercises/concept/cars-assemble/CarsAssembleTests.cs similarity index 100% rename from exercises/concept/numbers/NumbersTests.cs rename to exercises/concept/cars-assemble/CarsAssembleTests.cs diff --git a/exercises/concept/classes/.docs/hints.md b/exercises/concept/elons-toys/.docs/hints.md similarity index 100% rename from exercises/concept/classes/.docs/hints.md rename to exercises/concept/elons-toys/.docs/hints.md diff --git a/exercises/concept/classes/.docs/instructions.md b/exercises/concept/elons-toys/.docs/instructions.md similarity index 100% rename from exercises/concept/classes/.docs/instructions.md rename to exercises/concept/elons-toys/.docs/instructions.md diff --git a/exercises/concept/classes/.docs/introduction.md b/exercises/concept/elons-toys/.docs/introduction.md similarity index 100% rename from exercises/concept/classes/.docs/introduction.md rename to exercises/concept/elons-toys/.docs/introduction.md diff --git a/exercises/concept/classes/.meta/Example.cs b/exercises/concept/elons-toys/.meta/Example.cs similarity index 100% rename from exercises/concept/classes/.meta/Example.cs rename to exercises/concept/elons-toys/.meta/Example.cs diff --git a/exercises/concept/arrays/.meta/config.json b/exercises/concept/elons-toys/.meta/config.json similarity index 63% rename from exercises/concept/arrays/.meta/config.json rename to exercises/concept/elons-toys/.meta/config.json index 2603d89780..98c1f143b9 100644 --- a/exercises/concept/arrays/.meta/config.json +++ b/exercises/concept/elons-toys/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Arrays.cs"], - "test_files": ["ArraysTests.cs"] + "solution_files": ["ElonsToys.cs"], + "test_files": ["ElonsToysTests.cs"] } } diff --git a/exercises/concept/classes/.meta/design.md b/exercises/concept/elons-toys/.meta/design.md similarity index 100% rename from exercises/concept/classes/.meta/design.md rename to exercises/concept/elons-toys/.meta/design.md diff --git a/exercises/concept/classes/Classes.cs b/exercises/concept/elons-toys/ElonsToys.cs similarity index 100% rename from exercises/concept/classes/Classes.cs rename to exercises/concept/elons-toys/ElonsToys.cs diff --git a/exercises/concept/datetimes/DateTimes.csproj b/exercises/concept/elons-toys/ElonsToys.csproj similarity index 100% rename from exercises/concept/datetimes/DateTimes.csproj rename to exercises/concept/elons-toys/ElonsToys.csproj diff --git a/exercises/concept/classes/ClassesTests.cs b/exercises/concept/elons-toys/ElonsToysTests.cs similarity index 100% rename from exercises/concept/classes/ClassesTests.cs rename to exercises/concept/elons-toys/ElonsToysTests.cs diff --git a/exercises/concept/expression-bodied-members/.meta/config.json b/exercises/concept/expression-bodied-members/.meta/config.json deleted file mode 100644 index 4410a13244..0000000000 --- a/exercises/concept/expression-bodied-members/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Expression-bodied-members.cs"], - "test_files": ["Expression-bodied-membersTests.cs"] - } -} diff --git a/exercises/concept/equality/.docs/hints.md b/exercises/concept/faceid-2/.docs/hints.md similarity index 100% rename from exercises/concept/equality/.docs/hints.md rename to exercises/concept/faceid-2/.docs/hints.md diff --git a/exercises/concept/equality/.docs/instructions.md b/exercises/concept/faceid-2/.docs/instructions.md similarity index 100% rename from exercises/concept/equality/.docs/instructions.md rename to exercises/concept/faceid-2/.docs/instructions.md diff --git a/exercises/concept/equality/.docs/introduction.md b/exercises/concept/faceid-2/.docs/introduction.md similarity index 100% rename from exercises/concept/equality/.docs/introduction.md rename to exercises/concept/faceid-2/.docs/introduction.md diff --git a/exercises/concept/equality/.meta/Example.cs b/exercises/concept/faceid-2/.meta/Example.cs similarity index 100% rename from exercises/concept/equality/.meta/Example.cs rename to exercises/concept/faceid-2/.meta/Example.cs diff --git a/exercises/concept/chars/.meta/config.json b/exercises/concept/faceid-2/.meta/config.json similarity index 77% rename from exercises/concept/chars/.meta/config.json rename to exercises/concept/faceid-2/.meta/config.json index cbac7359ea..32e59905ae 100644 --- a/exercises/concept/chars/.meta/config.json +++ b/exercises/concept/faceid-2/.meta/config.json @@ -12,7 +12,7 @@ } ], "editor": { - "solution_files": ["Chars.cs"], - "test_files": ["CharsTests.cs"] + "solution_files": ["Faceid2.cs"], + "test_files": ["Faceid2Tests.cs"] } } diff --git a/exercises/concept/equality/.meta/design.md b/exercises/concept/faceid-2/.meta/design.md similarity index 100% rename from exercises/concept/equality/.meta/design.md rename to exercises/concept/faceid-2/.meta/design.md diff --git a/exercises/concept/equality/Equality.cs b/exercises/concept/faceid-2/Faceid2.cs similarity index 100% rename from exercises/concept/equality/Equality.cs rename to exercises/concept/faceid-2/Faceid2.cs diff --git a/exercises/concept/dictionaries/Dictionaries.csproj b/exercises/concept/faceid-2/Faceid2.csproj similarity index 100% rename from exercises/concept/dictionaries/Dictionaries.csproj rename to exercises/concept/faceid-2/Faceid2.csproj diff --git a/exercises/concept/equality/EqualityTests.cs b/exercises/concept/faceid-2/Faceid2Tests.cs similarity index 100% rename from exercises/concept/equality/EqualityTests.cs rename to exercises/concept/faceid-2/Faceid2Tests.cs diff --git a/exercises/concept/flag-enums/.meta/config.json b/exercises/concept/flag-enums/.meta/config.json deleted file mode 100644 index 1c99825fe2..0000000000 --- a/exercises/concept/flag-enums/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Flag-enums.cs"], - "test_files": ["Flag-enumsTests.cs"] - } -} diff --git a/exercises/concept/floating-point-numbers/.meta/config.json b/exercises/concept/floating-point-numbers/.meta/config.json deleted file mode 100644 index a93240e66e..0000000000 --- a/exercises/concept/floating-point-numbers/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Floating-point-numbers.cs"], - "test_files": ["Floating-point-numbersTests.cs"] - } -} diff --git a/exercises/concept/switch-statements/.docs/hints.md b/exercises/concept/football-match-reports/.docs/hints.md similarity index 100% rename from exercises/concept/switch-statements/.docs/hints.md rename to exercises/concept/football-match-reports/.docs/hints.md diff --git a/exercises/concept/switch-statements/.docs/instructions.md b/exercises/concept/football-match-reports/.docs/instructions.md similarity index 100% rename from exercises/concept/switch-statements/.docs/instructions.md rename to exercises/concept/football-match-reports/.docs/instructions.md diff --git a/exercises/concept/switch-statements/.docs/introduction.md b/exercises/concept/football-match-reports/.docs/introduction.md similarity index 100% rename from exercises/concept/switch-statements/.docs/introduction.md rename to exercises/concept/football-match-reports/.docs/introduction.md diff --git a/exercises/concept/switch-statements/.meta/Example.cs b/exercises/concept/football-match-reports/.meta/Example.cs similarity index 100% rename from exercises/concept/switch-statements/.meta/Example.cs rename to exercises/concept/football-match-reports/.meta/Example.cs diff --git a/exercises/concept/switch-statements/.meta/config.json b/exercises/concept/football-match-reports/.meta/config.json similarity index 77% rename from exercises/concept/switch-statements/.meta/config.json rename to exercises/concept/football-match-reports/.meta/config.json index b5489477f6..7181ca0f92 100644 --- a/exercises/concept/switch-statements/.meta/config.json +++ b/exercises/concept/football-match-reports/.meta/config.json @@ -16,7 +16,7 @@ } ], "editor": { - "solution_files": ["Switch-statements.cs"], - "test_files": ["Switch-statementsTests.cs"] + "solution_files": ["FootballMatchReports.cs"], + "test_files": ["FootballMatchReportsTests.cs"] } } diff --git a/exercises/concept/switch-statements/.meta/design.md b/exercises/concept/football-match-reports/.meta/design.md similarity index 100% rename from exercises/concept/switch-statements/.meta/design.md rename to exercises/concept/football-match-reports/.meta/design.md diff --git a/exercises/concept/switch-statements/SwitchStatements.cs b/exercises/concept/football-match-reports/FootballMatchReports.cs similarity index 100% rename from exercises/concept/switch-statements/SwitchStatements.cs rename to exercises/concept/football-match-reports/FootballMatchReports.cs diff --git a/exercises/concept/equality/Equality.csproj b/exercises/concept/football-match-reports/FootballMatchReports.csproj similarity index 100% rename from exercises/concept/equality/Equality.csproj rename to exercises/concept/football-match-reports/FootballMatchReports.csproj diff --git a/exercises/concept/switch-statements/SwitchStatementsTests.cs b/exercises/concept/football-match-reports/FootballMatchReportsTests.cs similarity index 100% rename from exercises/concept/switch-statements/SwitchStatementsTests.cs rename to exercises/concept/football-match-reports/FootballMatchReportsTests.cs diff --git a/exercises/concept/string-formatting/.docs/hints.md b/exercises/concept/high-school-sweethearts/.docs/hints.md similarity index 100% rename from exercises/concept/string-formatting/.docs/hints.md rename to exercises/concept/high-school-sweethearts/.docs/hints.md diff --git a/exercises/concept/string-formatting/.docs/instructions.md b/exercises/concept/high-school-sweethearts/.docs/instructions.md similarity index 100% rename from exercises/concept/string-formatting/.docs/instructions.md rename to exercises/concept/high-school-sweethearts/.docs/instructions.md diff --git a/exercises/concept/string-formatting/.docs/introduction.md b/exercises/concept/high-school-sweethearts/.docs/introduction.md similarity index 100% rename from exercises/concept/string-formatting/.docs/introduction.md rename to exercises/concept/high-school-sweethearts/.docs/introduction.md diff --git a/exercises/concept/string-formatting/.meta/Example.cs b/exercises/concept/high-school-sweethearts/.meta/Example.cs similarity index 100% rename from exercises/concept/string-formatting/.meta/Example.cs rename to exercises/concept/high-school-sweethearts/.meta/Example.cs diff --git a/exercises/concept/string-formatting/.meta/config.json b/exercises/concept/high-school-sweethearts/.meta/config.json similarity index 73% rename from exercises/concept/string-formatting/.meta/config.json rename to exercises/concept/high-school-sweethearts/.meta/config.json index 434fb5b0c0..afcbae6840 100644 --- a/exercises/concept/string-formatting/.meta/config.json +++ b/exercises/concept/high-school-sweethearts/.meta/config.json @@ -13,7 +13,7 @@ ], "forked_from": ["elixir/strings"], "editor": { - "solution_files": ["String-formatting.cs"], - "test_files": ["String-formattingTests.cs"] + "solution_files": ["HighSchoolSweethearts.cs"], + "test_files": ["HighSchoolSweetheartsTests.cs"] } } diff --git a/exercises/concept/string-formatting/.meta/design.md b/exercises/concept/high-school-sweethearts/.meta/design.md similarity index 100% rename from exercises/concept/string-formatting/.meta/design.md rename to exercises/concept/high-school-sweethearts/.meta/design.md diff --git a/exercises/concept/string-formatting/StringFormatting.cs b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs similarity index 100% rename from exercises/concept/string-formatting/StringFormatting.cs rename to exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj similarity index 100% rename from exercises/concept/expression-bodied-members/ExpressionBodiedMembers.csproj rename to exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj diff --git a/exercises/concept/string-formatting/StringFormattingTests.cs b/exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs similarity index 100% rename from exercises/concept/string-formatting/StringFormattingTests.cs rename to exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs diff --git a/exercises/concept/integral-numbers/.docs/hints.md b/exercises/concept/hyper-optimized-telemetry/.docs/hints.md similarity index 100% rename from exercises/concept/integral-numbers/.docs/hints.md rename to exercises/concept/hyper-optimized-telemetry/.docs/hints.md diff --git a/exercises/concept/integral-numbers/.docs/instructions.md b/exercises/concept/hyper-optimized-telemetry/.docs/instructions.md similarity index 100% rename from exercises/concept/integral-numbers/.docs/instructions.md rename to exercises/concept/hyper-optimized-telemetry/.docs/instructions.md diff --git a/exercises/concept/integral-numbers/.docs/introduction.md b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md similarity index 100% rename from exercises/concept/integral-numbers/.docs/introduction.md rename to exercises/concept/hyper-optimized-telemetry/.docs/introduction.md diff --git a/exercises/concept/integral-numbers/.meta/Example.cs b/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs similarity index 100% rename from exercises/concept/integral-numbers/.meta/Example.cs rename to exercises/concept/hyper-optimized-telemetry/.meta/Example.cs diff --git a/exercises/concept/hyper-optimized-telemetry/.meta/config.json b/exercises/concept/hyper-optimized-telemetry/.meta/config.json new file mode 100644 index 0000000000..a71a0f84a8 --- /dev/null +++ b/exercises/concept/hyper-optimized-telemetry/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["HyperOptimizedTelemetry.cs"], + "test_files": ["HyperOptimizedTelemetryTests.cs"] + } +} diff --git a/exercises/concept/integral-numbers/.meta/design.md b/exercises/concept/hyper-optimized-telemetry/.meta/design.md similarity index 100% rename from exercises/concept/integral-numbers/.meta/design.md rename to exercises/concept/hyper-optimized-telemetry/.meta/design.md diff --git a/exercises/concept/integral-numbers/IntegralNumbers.cs b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.cs similarity index 100% rename from exercises/concept/integral-numbers/IntegralNumbers.cs rename to exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.cs diff --git a/exercises/concept/integral-numbers/IntegralNumbers.csproj b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj similarity index 100% rename from exercises/concept/integral-numbers/IntegralNumbers.csproj rename to exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj diff --git a/exercises/concept/integral-numbers/IntegralNumbersTests.cs b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs similarity index 100% rename from exercises/concept/integral-numbers/IntegralNumbersTests.cs rename to exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs diff --git a/exercises/concept/operator-overloading/.docs/hints.md b/exercises/concept/hyperia-forex/.docs/hints.md similarity index 100% rename from exercises/concept/operator-overloading/.docs/hints.md rename to exercises/concept/hyperia-forex/.docs/hints.md diff --git a/exercises/concept/operator-overloading/.docs/instructions.md b/exercises/concept/hyperia-forex/.docs/instructions.md similarity index 100% rename from exercises/concept/operator-overloading/.docs/instructions.md rename to exercises/concept/hyperia-forex/.docs/instructions.md diff --git a/exercises/concept/operator-overloading/.docs/introduction.md b/exercises/concept/hyperia-forex/.docs/introduction.md similarity index 100% rename from exercises/concept/operator-overloading/.docs/introduction.md rename to exercises/concept/hyperia-forex/.docs/introduction.md diff --git a/exercises/concept/operator-overloading/.meta/Example.cs b/exercises/concept/hyperia-forex/.meta/Example.cs similarity index 100% rename from exercises/concept/operator-overloading/.meta/Example.cs rename to exercises/concept/hyperia-forex/.meta/Example.cs diff --git a/exercises/concept/dictionaries/.meta/config.json b/exercises/concept/hyperia-forex/.meta/config.json similarity index 74% rename from exercises/concept/dictionaries/.meta/config.json rename to exercises/concept/hyperia-forex/.meta/config.json index f9df5065c3..96eb928dce 100644 --- a/exercises/concept/dictionaries/.meta/config.json +++ b/exercises/concept/hyperia-forex/.meta/config.json @@ -12,7 +12,7 @@ } ], "editor": { - "solution_files": ["Dictionaries.cs"], - "test_files": ["DictionariesTests.cs"] + "solution_files": ["HyperiaForex.cs"], + "test_files": ["HyperiaForexTests.cs"] } } diff --git a/exercises/concept/operator-overloading/.meta/design.md b/exercises/concept/hyperia-forex/.meta/design.md similarity index 100% rename from exercises/concept/operator-overloading/.meta/design.md rename to exercises/concept/hyperia-forex/.meta/design.md diff --git a/exercises/concept/operator-overloading/OperatorOverloading.cs b/exercises/concept/hyperia-forex/HyperiaForex.cs similarity index 100% rename from exercises/concept/operator-overloading/OperatorOverloading.cs rename to exercises/concept/hyperia-forex/HyperiaForex.cs diff --git a/exercises/concept/interfaces/Interfaces.csproj b/exercises/concept/hyperia-forex/HyperiaForex.csproj similarity index 100% rename from exercises/concept/interfaces/Interfaces.csproj rename to exercises/concept/hyperia-forex/HyperiaForex.csproj diff --git a/exercises/concept/operator-overloading/OperatorOverloadingTests.cs b/exercises/concept/hyperia-forex/HyperiaForexTests.cs similarity index 100% rename from exercises/concept/operator-overloading/OperatorOverloadingTests.cs rename to exercises/concept/hyperia-forex/HyperiaForexTests.cs diff --git a/exercises/concept/overflow/.docs/hints.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md similarity index 100% rename from exercises/concept/overflow/.docs/hints.md rename to exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md diff --git a/exercises/concept/overflow/.docs/instructions.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md similarity index 100% rename from exercises/concept/overflow/.docs/instructions.md rename to exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md diff --git a/exercises/concept/overflow/.docs/introduction.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md similarity index 100% rename from exercises/concept/overflow/.docs/introduction.md rename to exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md diff --git a/exercises/concept/overflow/.meta/Example.cs b/exercises/concept/hyperinflation-hits-hyperia/.meta/Example.cs similarity index 100% rename from exercises/concept/overflow/.meta/Example.cs rename to exercises/concept/hyperinflation-hits-hyperia/.meta/Example.cs diff --git a/exercises/concept/overflow/.meta/config.json b/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json similarity index 82% rename from exercises/concept/overflow/.meta/config.json rename to exercises/concept/hyperinflation-hits-hyperia/.meta/config.json index d938e77487..34bc954d5e 100644 --- a/exercises/concept/overflow/.meta/config.json +++ b/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json @@ -24,7 +24,7 @@ } ], "editor": { - "solution_files": ["Overflow.cs"], - "test_files": ["OverflowTests.cs"] + "solution_files": ["HyperinflationHitsHyperia.cs"], + "test_files": ["HyperinflationHitsHyperiaTests.cs"] } } diff --git a/exercises/concept/overflow/.meta/design.md b/exercises/concept/hyperinflation-hits-hyperia/.meta/design.md similarity index 100% rename from exercises/concept/overflow/.meta/design.md rename to exercises/concept/hyperinflation-hits-hyperia/.meta/design.md diff --git a/exercises/concept/overflow/Overflow.cs b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.cs similarity index 100% rename from exercises/concept/overflow/Overflow.cs rename to exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.cs diff --git a/exercises/concept/lists/Lists.csproj b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj similarity index 100% rename from exercises/concept/lists/Lists.csproj rename to exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj diff --git a/exercises/concept/overflow/OverflowTests.cs b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs similarity index 100% rename from exercises/concept/overflow/OverflowTests.cs rename to exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs diff --git a/exercises/concept/inheritance/.meta/config.json b/exercises/concept/inheritance/.meta/config.json deleted file mode 100644 index 9b7896684e..0000000000 --- a/exercises/concept/inheritance/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Inheritance.cs"], - "test_files": ["InheritanceTests.cs"] - } -} diff --git a/exercises/concept/user-defined-exceptions/.docs/hints.md b/exercises/concept/instruments-of-texas/.docs/hints.md similarity index 100% rename from exercises/concept/user-defined-exceptions/.docs/hints.md rename to exercises/concept/instruments-of-texas/.docs/hints.md diff --git a/exercises/concept/user-defined-exceptions/.docs/instructions.md b/exercises/concept/instruments-of-texas/.docs/instructions.md similarity index 100% rename from exercises/concept/user-defined-exceptions/.docs/instructions.md rename to exercises/concept/instruments-of-texas/.docs/instructions.md diff --git a/exercises/concept/user-defined-exceptions/.docs/introduction.md b/exercises/concept/instruments-of-texas/.docs/introduction.md similarity index 100% rename from exercises/concept/user-defined-exceptions/.docs/introduction.md rename to exercises/concept/instruments-of-texas/.docs/introduction.md diff --git a/exercises/concept/user-defined-exceptions/.meta/Example.cs b/exercises/concept/instruments-of-texas/.meta/Example.cs similarity index 100% rename from exercises/concept/user-defined-exceptions/.meta/Example.cs rename to exercises/concept/instruments-of-texas/.meta/Example.cs diff --git a/exercises/concept/user-defined-exceptions/.meta/config.json b/exercises/concept/instruments-of-texas/.meta/config.json similarity index 72% rename from exercises/concept/user-defined-exceptions/.meta/config.json rename to exercises/concept/instruments-of-texas/.meta/config.json index 5b55090379..b9d4523800 100644 --- a/exercises/concept/user-defined-exceptions/.meta/config.json +++ b/exercises/concept/instruments-of-texas/.meta/config.json @@ -13,7 +13,7 @@ ], "forked_from": ["elixir/errors"], "editor": { - "solution_files": ["User-defined-exceptions.cs"], - "test_files": ["User-defined-exceptionsTests.cs"] + "solution_files": ["InstrumentsOfTexas.cs"], + "test_files": ["InstrumentsOfTexasTests.cs"] } } diff --git a/exercises/concept/user-defined-exceptions/.meta/design.md b/exercises/concept/instruments-of-texas/.meta/design.md similarity index 100% rename from exercises/concept/user-defined-exceptions/.meta/design.md rename to exercises/concept/instruments-of-texas/.meta/design.md diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.cs similarity index 100% rename from exercises/concept/user-defined-exceptions/UserDefinedExceptons.cs rename to exercises/concept/instruments-of-texas/InstrumentsOfTexas.cs diff --git a/exercises/concept/namespaces/Namespaces.csproj b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj similarity index 100% rename from exercises/concept/namespaces/Namespaces.csproj rename to exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs b/exercises/concept/instruments-of-texas/InstrumentsOfTexasTests.cs similarity index 100% rename from exercises/concept/user-defined-exceptions/UserDefinedExceptionsTests.cs rename to exercises/concept/instruments-of-texas/InstrumentsOfTexasTests.cs diff --git a/exercises/concept/integral-numbers/.meta/config.json b/exercises/concept/integral-numbers/.meta/config.json deleted file mode 100644 index cb561a5e51..0000000000 --- a/exercises/concept/integral-numbers/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Integral-numbers.cs"], - "test_files": ["Integral-numbersTests.cs"] - } -} diff --git a/exercises/concept/floating-point-numbers/.docs/hints.md b/exercises/concept/interest-is-interesting/.docs/hints.md similarity index 100% rename from exercises/concept/floating-point-numbers/.docs/hints.md rename to exercises/concept/interest-is-interesting/.docs/hints.md diff --git a/exercises/concept/floating-point-numbers/.docs/instructions.md b/exercises/concept/interest-is-interesting/.docs/instructions.md similarity index 100% rename from exercises/concept/floating-point-numbers/.docs/instructions.md rename to exercises/concept/interest-is-interesting/.docs/instructions.md diff --git a/exercises/concept/floating-point-numbers/.docs/introduction.md b/exercises/concept/interest-is-interesting/.docs/introduction.md similarity index 100% rename from exercises/concept/floating-point-numbers/.docs/introduction.md rename to exercises/concept/interest-is-interesting/.docs/introduction.md diff --git a/exercises/concept/floating-point-numbers/.meta/Example.cs b/exercises/concept/interest-is-interesting/.meta/Example.cs similarity index 100% rename from exercises/concept/floating-point-numbers/.meta/Example.cs rename to exercises/concept/interest-is-interesting/.meta/Example.cs diff --git a/exercises/concept/interest-is-interesting/.meta/config.json b/exercises/concept/interest-is-interesting/.meta/config.json new file mode 100644 index 0000000000..920a82b250 --- /dev/null +++ b/exercises/concept/interest-is-interesting/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["InterestIsInteresting.cs"], + "test_files": ["InterestIsInterestingTests.cs"] + } +} diff --git a/exercises/concept/floating-point-numbers/.meta/design.md b/exercises/concept/interest-is-interesting/.meta/design.md similarity index 100% rename from exercises/concept/floating-point-numbers/.meta/design.md rename to exercises/concept/interest-is-interesting/.meta/design.md diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.cs b/exercises/concept/interest-is-interesting/InterestIsInteresting.cs similarity index 100% rename from exercises/concept/floating-point-numbers/FloatingPointNumbers.cs rename to exercises/concept/interest-is-interesting/InterestIsInteresting.cs diff --git a/exercises/concept/enums/Enums.csproj b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj similarity index 100% rename from exercises/concept/enums/Enums.csproj rename to exercises/concept/interest-is-interesting/InterestIsInteresting.csproj diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs b/exercises/concept/interest-is-interesting/InterestIsInterestingTests.cs similarity index 100% rename from exercises/concept/floating-point-numbers/FloatingPointNumbersTests.cs rename to exercises/concept/interest-is-interesting/InterestIsInterestingTests.cs diff --git a/exercises/concept/dictionaries/.docs/hints.md b/exercises/concept/international-calling-connoisseur/.docs/hints.md similarity index 100% rename from exercises/concept/dictionaries/.docs/hints.md rename to exercises/concept/international-calling-connoisseur/.docs/hints.md diff --git a/exercises/concept/dictionaries/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md similarity index 100% rename from exercises/concept/dictionaries/.docs/instructions.md rename to exercises/concept/international-calling-connoisseur/.docs/instructions.md diff --git a/exercises/concept/dictionaries/.docs/introduction.md b/exercises/concept/international-calling-connoisseur/.docs/introduction.md similarity index 100% rename from exercises/concept/dictionaries/.docs/introduction.md rename to exercises/concept/international-calling-connoisseur/.docs/introduction.md diff --git a/exercises/concept/dictionaries/.meta/Example.cs b/exercises/concept/international-calling-connoisseur/.meta/Example.cs similarity index 100% rename from exercises/concept/dictionaries/.meta/Example.cs rename to exercises/concept/international-calling-connoisseur/.meta/Example.cs diff --git a/exercises/concept/international-calling-connoisseur/.meta/config.json b/exercises/concept/international-calling-connoisseur/.meta/config.json new file mode 100644 index 0000000000..66c9974787 --- /dev/null +++ b/exercises/concept/international-calling-connoisseur/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["InternationalCallingConnoisseur.cs"], + "test_files": ["InternationalCallingConnoisseurTests.cs"] + } +} diff --git a/exercises/concept/dictionaries/.meta/design.md b/exercises/concept/international-calling-connoisseur/.meta/design.md similarity index 100% rename from exercises/concept/dictionaries/.meta/design.md rename to exercises/concept/international-calling-connoisseur/.meta/design.md diff --git a/exercises/concept/dictionaries/Dictionaries.cs b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs similarity index 100% rename from exercises/concept/dictionaries/Dictionaries.cs rename to exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs diff --git a/exercises/concept/nested-types/NestedTypes.csproj b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj similarity index 100% rename from exercises/concept/nested-types/NestedTypes.csproj rename to exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj diff --git a/exercises/concept/dictionaries/DictionariesTests.cs b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs similarity index 100% rename from exercises/concept/dictionaries/DictionariesTests.cs rename to exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs diff --git a/exercises/concept/structs/.docs/hints.md b/exercises/concept/land-grab-in-space/.docs/hints.md similarity index 100% rename from exercises/concept/structs/.docs/hints.md rename to exercises/concept/land-grab-in-space/.docs/hints.md diff --git a/exercises/concept/structs/.docs/instructions.md b/exercises/concept/land-grab-in-space/.docs/instructions.md similarity index 100% rename from exercises/concept/structs/.docs/instructions.md rename to exercises/concept/land-grab-in-space/.docs/instructions.md diff --git a/exercises/concept/structs/.docs/introduction.md b/exercises/concept/land-grab-in-space/.docs/introduction.md similarity index 100% rename from exercises/concept/structs/.docs/introduction.md rename to exercises/concept/land-grab-in-space/.docs/introduction.md diff --git a/exercises/concept/structs/.meta/Example.cs b/exercises/concept/land-grab-in-space/.meta/Example.cs similarity index 100% rename from exercises/concept/structs/.meta/Example.cs rename to exercises/concept/land-grab-in-space/.meta/Example.cs diff --git a/exercises/concept/structs/.meta/config.json b/exercises/concept/land-grab-in-space/.meta/config.json similarity index 81% rename from exercises/concept/structs/.meta/config.json rename to exercises/concept/land-grab-in-space/.meta/config.json index 04e20562f4..e638703ef5 100644 --- a/exercises/concept/structs/.meta/config.json +++ b/exercises/concept/land-grab-in-space/.meta/config.json @@ -20,7 +20,7 @@ } ], "editor": { - "solution_files": ["Structs.cs"], - "test_files": ["StructsTests.cs"] + "solution_files": ["LandGrabInSpace.cs"], + "test_files": ["LandGrabInSpaceTests.cs"] } } diff --git a/exercises/concept/structs/.meta/design.md b/exercises/concept/land-grab-in-space/.meta/design.md similarity index 100% rename from exercises/concept/structs/.meta/design.md rename to exercises/concept/land-grab-in-space/.meta/design.md diff --git a/exercises/concept/structs/Structs.cs b/exercises/concept/land-grab-in-space/LandGrabInSpace.cs similarity index 100% rename from exercises/concept/structs/Structs.cs rename to exercises/concept/land-grab-in-space/LandGrabInSpace.cs diff --git a/exercises/concept/object-initializers/ObjectInitialization.csproj b/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj similarity index 100% rename from exercises/concept/object-initializers/ObjectInitialization.csproj rename to exercises/concept/land-grab-in-space/LandGrabInSpace.csproj diff --git a/exercises/concept/structs/StructsTests.cs b/exercises/concept/land-grab-in-space/LandGrabInSpaceTests.cs similarity index 100% rename from exercises/concept/structs/StructsTests.cs rename to exercises/concept/land-grab-in-space/LandGrabInSpaceTests.cs diff --git a/exercises/concept/strings/.docs/hints.md b/exercises/concept/log-levels/.docs/hints.md similarity index 100% rename from exercises/concept/strings/.docs/hints.md rename to exercises/concept/log-levels/.docs/hints.md diff --git a/exercises/concept/strings/.docs/instructions.md b/exercises/concept/log-levels/.docs/instructions.md similarity index 100% rename from exercises/concept/strings/.docs/instructions.md rename to exercises/concept/log-levels/.docs/instructions.md diff --git a/exercises/concept/strings/.docs/introduction.md b/exercises/concept/log-levels/.docs/introduction.md similarity index 100% rename from exercises/concept/strings/.docs/introduction.md rename to exercises/concept/log-levels/.docs/introduction.md diff --git a/exercises/concept/strings/.meta/Example.cs b/exercises/concept/log-levels/.meta/Example.cs similarity index 100% rename from exercises/concept/strings/.meta/Example.cs rename to exercises/concept/log-levels/.meta/Example.cs diff --git a/exercises/concept/datetimes/.meta/config.json b/exercises/concept/log-levels/.meta/config.json similarity index 63% rename from exercises/concept/datetimes/.meta/config.json rename to exercises/concept/log-levels/.meta/config.json index c0cb68eee3..ce108742a4 100644 --- a/exercises/concept/datetimes/.meta/config.json +++ b/exercises/concept/log-levels/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Datetimes.cs"], - "test_files": ["DatetimesTests.cs"] + "solution_files": ["LogLevels.cs"], + "test_files": ["LogLevelsTests.cs"] } } diff --git a/exercises/concept/strings/.meta/design.md b/exercises/concept/log-levels/.meta/design.md similarity index 100% rename from exercises/concept/strings/.meta/design.md rename to exercises/concept/log-levels/.meta/design.md diff --git a/exercises/concept/strings/Strings.cs b/exercises/concept/log-levels/LogLevels.cs similarity index 100% rename from exercises/concept/strings/Strings.cs rename to exercises/concept/log-levels/LogLevels.cs diff --git a/exercises/concept/flag-enums/FlagEnums.csproj b/exercises/concept/log-levels/LogLevels.csproj similarity index 100% rename from exercises/concept/flag-enums/FlagEnums.csproj rename to exercises/concept/log-levels/LogLevels.csproj diff --git a/exercises/concept/strings/StringsTests.cs b/exercises/concept/log-levels/LogLevelsTests.cs similarity index 100% rename from exercises/concept/strings/StringsTests.cs rename to exercises/concept/log-levels/LogLevelsTests.cs diff --git a/exercises/concept/enums/.docs/hints.md b/exercises/concept/logs-logs-logs/.docs/hints.md similarity index 100% rename from exercises/concept/enums/.docs/hints.md rename to exercises/concept/logs-logs-logs/.docs/hints.md diff --git a/exercises/concept/enums/.docs/instructions.md b/exercises/concept/logs-logs-logs/.docs/instructions.md similarity index 100% rename from exercises/concept/enums/.docs/instructions.md rename to exercises/concept/logs-logs-logs/.docs/instructions.md diff --git a/exercises/concept/enums/.docs/introduction.md b/exercises/concept/logs-logs-logs/.docs/introduction.md similarity index 100% rename from exercises/concept/enums/.docs/introduction.md rename to exercises/concept/logs-logs-logs/.docs/introduction.md diff --git a/exercises/concept/enums/.meta/Example.cs b/exercises/concept/logs-logs-logs/.meta/Example.cs similarity index 100% rename from exercises/concept/enums/.meta/Example.cs rename to exercises/concept/logs-logs-logs/.meta/Example.cs diff --git a/exercises/concept/classes/.meta/config.json b/exercises/concept/logs-logs-logs/.meta/config.json similarity index 62% rename from exercises/concept/classes/.meta/config.json rename to exercises/concept/logs-logs-logs/.meta/config.json index ae84c97d6c..e1f564f856 100644 --- a/exercises/concept/classes/.meta/config.json +++ b/exercises/concept/logs-logs-logs/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Classes.cs"], - "test_files": ["ClassesTests.cs"] + "solution_files": ["LogsLogsLogs.cs"], + "test_files": ["LogsLogsLogsTests.cs"] } } diff --git a/exercises/concept/enums/.meta/design.md b/exercises/concept/logs-logs-logs/.meta/design.md similarity index 100% rename from exercises/concept/enums/.meta/design.md rename to exercises/concept/logs-logs-logs/.meta/design.md diff --git a/exercises/concept/enums/Enums.cs b/exercises/concept/logs-logs-logs/LogsLogsLogs.cs similarity index 100% rename from exercises/concept/enums/Enums.cs rename to exercises/concept/logs-logs-logs/LogsLogsLogs.cs diff --git a/exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj similarity index 100% rename from exercises/concept/floating-point-numbers/FloatingPointNumbers.csproj rename to exercises/concept/logs-logs-logs/LogsLogsLogs.csproj diff --git a/exercises/concept/enums/EnumsTests.cs b/exercises/concept/logs-logs-logs/LogsLogsLogsTests.cs similarity index 100% rename from exercises/concept/enums/EnumsTests.cs rename to exercises/concept/logs-logs-logs/LogsLogsLogsTests.cs diff --git a/exercises/concept/basics/.docs/hints.md b/exercises/concept/lucians-luscious-lasagna/.docs/hints.md similarity index 100% rename from exercises/concept/basics/.docs/hints.md rename to exercises/concept/lucians-luscious-lasagna/.docs/hints.md diff --git a/exercises/concept/basics/.docs/instructions.md b/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md similarity index 100% rename from exercises/concept/basics/.docs/instructions.md rename to exercises/concept/lucians-luscious-lasagna/.docs/instructions.md diff --git a/exercises/concept/basics/.docs/introduction.md b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md similarity index 100% rename from exercises/concept/basics/.docs/introduction.md rename to exercises/concept/lucians-luscious-lasagna/.docs/introduction.md diff --git a/exercises/concept/basics/.meta/Example.cs b/exercises/concept/lucians-luscious-lasagna/.meta/Example.cs similarity index 100% rename from exercises/concept/basics/.meta/Example.cs rename to exercises/concept/lucians-luscious-lasagna/.meta/Example.cs diff --git a/exercises/concept/basics/.meta/config.json b/exercises/concept/lucians-luscious-lasagna/.meta/config.json similarity index 62% rename from exercises/concept/basics/.meta/config.json rename to exercises/concept/lucians-luscious-lasagna/.meta/config.json index 9f79d8afa1..d1d6d86368 100644 --- a/exercises/concept/basics/.meta/config.json +++ b/exercises/concept/lucians-luscious-lasagna/.meta/config.json @@ -7,7 +7,7 @@ ], "forked_from": ["fsharp/basics"], "editor": { - "solution_files": ["Basics.cs"], - "test_files": ["BasicsTests.cs"] + "solution_files": ["LuciansLusciousLasagna.cs"], + "test_files": ["LuciansLusciousLasagnaTests.cs"] } } diff --git a/exercises/concept/basics/.meta/design.md b/exercises/concept/lucians-luscious-lasagna/.meta/design.md similarity index 100% rename from exercises/concept/basics/.meta/design.md rename to exercises/concept/lucians-luscious-lasagna/.meta/design.md diff --git a/exercises/concept/basics/Basics.cs b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.cs similarity index 100% rename from exercises/concept/basics/Basics.cs rename to exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.cs diff --git a/exercises/concept/inheritance/Inheritance.csproj b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj similarity index 100% rename from exercises/concept/inheritance/Inheritance.csproj rename to exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj diff --git a/exercises/concept/basics/BasicsTests.cs b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagnaTests.cs similarity index 100% rename from exercises/concept/basics/BasicsTests.cs rename to exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagnaTests.cs diff --git a/exercises/concept/method-overloading/.meta/config.json b/exercises/concept/method-overloading/.meta/config.json deleted file mode 100644 index 101e6ec79a..0000000000 --- a/exercises/concept/method-overloading/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Method-overloading.cs"], - "test_files": ["Method-overloadingTests.cs"] - } -} diff --git a/exercises/concept/namespaces/.meta/config.json b/exercises/concept/namespaces/.meta/config.json deleted file mode 100644 index 070b277110..0000000000 --- a/exercises/concept/namespaces/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Namespaces.cs"], - "test_files": ["NamespacesTests.cs"] - } -} diff --git a/exercises/concept/constructors/.docs/hints.md b/exercises/concept/need-for-speed/.docs/hints.md similarity index 100% rename from exercises/concept/constructors/.docs/hints.md rename to exercises/concept/need-for-speed/.docs/hints.md diff --git a/exercises/concept/constructors/.docs/instructions.md b/exercises/concept/need-for-speed/.docs/instructions.md similarity index 100% rename from exercises/concept/constructors/.docs/instructions.md rename to exercises/concept/need-for-speed/.docs/instructions.md diff --git a/exercises/concept/constructors/.docs/introduction.md b/exercises/concept/need-for-speed/.docs/introduction.md similarity index 100% rename from exercises/concept/constructors/.docs/introduction.md rename to exercises/concept/need-for-speed/.docs/introduction.md diff --git a/exercises/concept/constructors/.meta/Example.cs b/exercises/concept/need-for-speed/.meta/Example.cs similarity index 100% rename from exercises/concept/constructors/.meta/Example.cs rename to exercises/concept/need-for-speed/.meta/Example.cs diff --git a/exercises/concept/need-for-speed/.meta/config.json b/exercises/concept/need-for-speed/.meta/config.json new file mode 100644 index 0000000000..d2d6811505 --- /dev/null +++ b/exercises/concept/need-for-speed/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["NeedForSpeed.cs"], + "test_files": ["NeedForSpeedTests.cs"] + } +} diff --git a/exercises/concept/constructors/.meta/design.md b/exercises/concept/need-for-speed/.meta/design.md similarity index 100% rename from exercises/concept/constructors/.meta/design.md rename to exercises/concept/need-for-speed/.meta/design.md diff --git a/exercises/concept/constructors/Constructors.cs b/exercises/concept/need-for-speed/NeedForSpeed.cs similarity index 100% rename from exercises/concept/constructors/Constructors.cs rename to exercises/concept/need-for-speed/NeedForSpeed.cs diff --git a/exercises/concept/method-overloading/MethodOverloading.csproj b/exercises/concept/need-for-speed/NeedForSpeed.csproj similarity index 100% rename from exercises/concept/method-overloading/MethodOverloading.csproj rename to exercises/concept/need-for-speed/NeedForSpeed.csproj diff --git a/exercises/concept/constructors/ConstructorsTests.cs b/exercises/concept/need-for-speed/NeedForSpeedTests.cs similarity index 100% rename from exercises/concept/constructors/ConstructorsTests.cs rename to exercises/concept/need-for-speed/NeedForSpeedTests.cs diff --git a/exercises/concept/nested-types/.meta/config.json b/exercises/concept/nested-types/.meta/config.json deleted file mode 100644 index eefecd618c..0000000000 --- a/exercises/concept/nested-types/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Nested-types.cs"], - "test_files": ["Nested-typesTests.cs"] - } -} diff --git a/exercises/concept/numbers/.meta/config.json b/exercises/concept/numbers/.meta/config.json deleted file mode 100644 index 116f250d56..0000000000 --- a/exercises/concept/numbers/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Numbers.cs"], - "test_files": ["NumbersTests.cs"] - } -} diff --git a/exercises/concept/object-initializers/.meta/config.json b/exercises/concept/object-initializers/.meta/config.json deleted file mode 100644 index d56705fb8d..0000000000 --- a/exercises/concept/object-initializers/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Object-initializers.cs"], - "test_files": ["Object-initializersTests.cs"] - } -} diff --git a/exercises/concept/resource-cleanup/.docs/hints.md b/exercises/concept/object-relational-mapping/.docs/hints.md similarity index 100% rename from exercises/concept/resource-cleanup/.docs/hints.md rename to exercises/concept/object-relational-mapping/.docs/hints.md diff --git a/exercises/concept/resource-cleanup/.docs/instructions.md b/exercises/concept/object-relational-mapping/.docs/instructions.md similarity index 100% rename from exercises/concept/resource-cleanup/.docs/instructions.md rename to exercises/concept/object-relational-mapping/.docs/instructions.md diff --git a/exercises/concept/resource-cleanup/.docs/introduction.md b/exercises/concept/object-relational-mapping/.docs/introduction.md similarity index 100% rename from exercises/concept/resource-cleanup/.docs/introduction.md rename to exercises/concept/object-relational-mapping/.docs/introduction.md diff --git a/exercises/concept/resource-cleanup/.meta/Example.cs b/exercises/concept/object-relational-mapping/.meta/Example.cs similarity index 100% rename from exercises/concept/resource-cleanup/.meta/Example.cs rename to exercises/concept/object-relational-mapping/.meta/Example.cs diff --git a/exercises/concept/object-relational-mapping/.meta/config.json b/exercises/concept/object-relational-mapping/.meta/config.json new file mode 100644 index 0000000000..9f45774b41 --- /dev/null +++ b/exercises/concept/object-relational-mapping/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["ObjectRelationalMapping.cs"], + "test_files": ["ObjectRelationalMappingTests.cs"] + } +} diff --git a/exercises/concept/resource-cleanup/.meta/design.md b/exercises/concept/object-relational-mapping/.meta/design.md similarity index 100% rename from exercises/concept/resource-cleanup/.meta/design.md rename to exercises/concept/object-relational-mapping/.meta/design.md diff --git a/exercises/concept/resource-cleanup/ResourceCleanup.cs b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.cs similarity index 100% rename from exercises/concept/resource-cleanup/ResourceCleanup.cs rename to exercises/concept/object-relational-mapping/ObjectRelationalMapping.cs diff --git a/exercises/concept/operator-overloading/OperatorOverloading.csproj b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj similarity index 100% rename from exercises/concept/operator-overloading/OperatorOverloading.csproj rename to exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj diff --git a/exercises/concept/resource-cleanup/ResourceCleanupTests.cs b/exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs similarity index 100% rename from exercises/concept/resource-cleanup/ResourceCleanupTests.cs rename to exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs diff --git a/exercises/concept/operator-overloading/.meta/config.json b/exercises/concept/operator-overloading/.meta/config.json deleted file mode 100644 index f55450964f..0000000000 --- a/exercises/concept/operator-overloading/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Operator-overloading.cs"], - "test_files": ["Operator-overloadingTests.cs"] - } -} diff --git a/exercises/concept/resource-lifetime/.docs/hints.md b/exercises/concept/orm-in-one-go/.docs/hints.md similarity index 100% rename from exercises/concept/resource-lifetime/.docs/hints.md rename to exercises/concept/orm-in-one-go/.docs/hints.md diff --git a/exercises/concept/resource-lifetime/.docs/instructions.md b/exercises/concept/orm-in-one-go/.docs/instructions.md similarity index 100% rename from exercises/concept/resource-lifetime/.docs/instructions.md rename to exercises/concept/orm-in-one-go/.docs/instructions.md diff --git a/exercises/concept/resource-lifetime/.docs/introduction.md b/exercises/concept/orm-in-one-go/.docs/introduction.md similarity index 100% rename from exercises/concept/resource-lifetime/.docs/introduction.md rename to exercises/concept/orm-in-one-go/.docs/introduction.md diff --git a/exercises/concept/resource-lifetime/.meta/Example.cs b/exercises/concept/orm-in-one-go/.meta/Example.cs similarity index 100% rename from exercises/concept/resource-lifetime/.meta/Example.cs rename to exercises/concept/orm-in-one-go/.meta/Example.cs diff --git a/exercises/concept/constants/.meta/config.json b/exercises/concept/orm-in-one-go/.meta/config.json similarity index 75% rename from exercises/concept/constants/.meta/config.json rename to exercises/concept/orm-in-one-go/.meta/config.json index 94cb362993..30c55d319e 100644 --- a/exercises/concept/constants/.meta/config.json +++ b/exercises/concept/orm-in-one-go/.meta/config.json @@ -12,7 +12,7 @@ } ], "editor": { - "solution_files": ["Constants.cs"], - "test_files": ["ConstantsTests.cs"] + "solution_files": ["OrmInOneGo.cs"], + "test_files": ["OrmInOneGoTests.cs"] } } diff --git a/exercises/concept/resource-lifetime/.meta/design.md b/exercises/concept/orm-in-one-go/.meta/design.md similarity index 100% rename from exercises/concept/resource-lifetime/.meta/design.md rename to exercises/concept/orm-in-one-go/.meta/design.md diff --git a/exercises/concept/resource-lifetime/ResourceLifetime.cs b/exercises/concept/orm-in-one-go/OrmInOneGo.cs similarity index 100% rename from exercises/concept/resource-lifetime/ResourceLifetime.cs rename to exercises/concept/orm-in-one-go/OrmInOneGo.cs diff --git a/exercises/concept/overflow/Overflow.csproj b/exercises/concept/orm-in-one-go/OrmInOneGo.csproj similarity index 100% rename from exercises/concept/overflow/Overflow.csproj rename to exercises/concept/orm-in-one-go/OrmInOneGo.csproj diff --git a/exercises/concept/resource-lifetime/ResourceLifetimeTests.cs b/exercises/concept/orm-in-one-go/OrmInOneGoTests.cs similarity index 100% rename from exercises/concept/resource-lifetime/ResourceLifetimeTests.cs rename to exercises/concept/orm-in-one-go/OrmInOneGoTests.cs diff --git a/exercises/concept/parameters/.meta/config.json b/exercises/concept/parameters/.meta/config.json deleted file mode 100644 index e1b9aab9ff..0000000000 --- a/exercises/concept/parameters/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Parameters.cs"], - "test_files": ["ParametersTests.cs"] - } -} diff --git a/exercises/concept/regular-expressions/.docs/hints.md b/exercises/concept/parsing-log-files/.docs/hints.md similarity index 100% rename from exercises/concept/regular-expressions/.docs/hints.md rename to exercises/concept/parsing-log-files/.docs/hints.md diff --git a/exercises/concept/regular-expressions/.docs/instructions.md b/exercises/concept/parsing-log-files/.docs/instructions.md similarity index 100% rename from exercises/concept/regular-expressions/.docs/instructions.md rename to exercises/concept/parsing-log-files/.docs/instructions.md diff --git a/exercises/concept/regular-expressions/.docs/introduction.md b/exercises/concept/parsing-log-files/.docs/introduction.md similarity index 100% rename from exercises/concept/regular-expressions/.docs/introduction.md rename to exercises/concept/parsing-log-files/.docs/introduction.md diff --git a/exercises/concept/regular-expressions/.meta/Example.cs b/exercises/concept/parsing-log-files/.meta/Example.cs similarity index 100% rename from exercises/concept/regular-expressions/.meta/Example.cs rename to exercises/concept/parsing-log-files/.meta/Example.cs diff --git a/exercises/concept/parsing-log-files/.meta/config.json b/exercises/concept/parsing-log-files/.meta/config.json new file mode 100644 index 0000000000..76dedb1f8b --- /dev/null +++ b/exercises/concept/parsing-log-files/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["ParsingLogFiles.cs"], + "test_files": ["ParsingLogFilesTests.cs"] + } +} diff --git a/exercises/concept/regular-expressions/.meta/design.md b/exercises/concept/parsing-log-files/.meta/design.md similarity index 100% rename from exercises/concept/regular-expressions/.meta/design.md rename to exercises/concept/parsing-log-files/.meta/design.md diff --git a/exercises/concept/regular-expressions/RegularExpressions.cs b/exercises/concept/parsing-log-files/ParsingLogFiles.cs similarity index 100% rename from exercises/concept/regular-expressions/RegularExpressions.cs rename to exercises/concept/parsing-log-files/ParsingLogFiles.cs diff --git a/exercises/concept/parameters/Parameters.csproj b/exercises/concept/parsing-log-files/ParsingLogFiles.csproj similarity index 100% rename from exercises/concept/parameters/Parameters.csproj rename to exercises/concept/parsing-log-files/ParsingLogFiles.csproj diff --git a/exercises/concept/regular-expressions/RegularExpressionsTests.cs b/exercises/concept/parsing-log-files/ParsingLogFilesTests.cs similarity index 100% rename from exercises/concept/regular-expressions/RegularExpressionsTests.cs rename to exercises/concept/parsing-log-files/ParsingLogFilesTests.cs diff --git a/exercises/concept/tuples/.docs/hints.md b/exercises/concept/phone-number-analysis/.docs/hints.md similarity index 100% rename from exercises/concept/tuples/.docs/hints.md rename to exercises/concept/phone-number-analysis/.docs/hints.md diff --git a/exercises/concept/tuples/.docs/instructions.md b/exercises/concept/phone-number-analysis/.docs/instructions.md similarity index 100% rename from exercises/concept/tuples/.docs/instructions.md rename to exercises/concept/phone-number-analysis/.docs/instructions.md diff --git a/exercises/concept/tuples/.docs/introduction.md b/exercises/concept/phone-number-analysis/.docs/introduction.md similarity index 100% rename from exercises/concept/tuples/.docs/introduction.md rename to exercises/concept/phone-number-analysis/.docs/introduction.md diff --git a/exercises/concept/tuples/.meta/Example.cs b/exercises/concept/phone-number-analysis/.meta/Example.cs similarity index 100% rename from exercises/concept/tuples/.meta/Example.cs rename to exercises/concept/phone-number-analysis/.meta/Example.cs diff --git a/exercises/concept/phone-number-analysis/.meta/config.json b/exercises/concept/phone-number-analysis/.meta/config.json new file mode 100644 index 0000000000..d8a4b32c0c --- /dev/null +++ b/exercises/concept/phone-number-analysis/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["PhoneNumberAnalysis.cs"], + "test_files": ["PhoneNumberAnalysisTests.cs"] + } +} diff --git a/exercises/concept/tuples/.meta/design.md b/exercises/concept/phone-number-analysis/.meta/design.md similarity index 100% rename from exercises/concept/tuples/.meta/design.md rename to exercises/concept/phone-number-analysis/.meta/design.md diff --git a/exercises/concept/tuples/Tuples.cs b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.cs similarity index 100% rename from exercises/concept/tuples/Tuples.cs rename to exercises/concept/phone-number-analysis/PhoneNumberAnalysis.cs diff --git a/exercises/concept/tuples/Tuples.csproj b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj similarity index 100% rename from exercises/concept/tuples/Tuples.csproj rename to exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj diff --git a/exercises/concept/tuples/TuplesTest.cs b/exercises/concept/phone-number-analysis/PhoneNumberAnalysisTests.cs similarity index 100% rename from exercises/concept/tuples/TuplesTest.cs rename to exercises/concept/phone-number-analysis/PhoneNumberAnalysisTests.cs diff --git a/exercises/concept/properties/.meta/config.json b/exercises/concept/properties/.meta/config.json deleted file mode 100644 index 38c3bcb7df..0000000000 --- a/exercises/concept/properties/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Properties.cs"], - "test_files": ["PropertiesTests.cs"] - } -} diff --git a/exercises/concept/randomness/.meta/config.json b/exercises/concept/randomness/.meta/config.json deleted file mode 100644 index 569be34f36..0000000000 --- a/exercises/concept/randomness/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Randomness.cs"], - "test_files": ["RandomnessTests.cs"] - } -} diff --git a/exercises/concept/namespaces/.docs/hints.md b/exercises/concept/red-vs-blue-darwin-style/.docs/hints.md similarity index 100% rename from exercises/concept/namespaces/.docs/hints.md rename to exercises/concept/red-vs-blue-darwin-style/.docs/hints.md diff --git a/exercises/concept/namespaces/.docs/instructions.md b/exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md similarity index 100% rename from exercises/concept/namespaces/.docs/instructions.md rename to exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md diff --git a/exercises/concept/namespaces/.docs/introduction.md b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md similarity index 100% rename from exercises/concept/namespaces/.docs/introduction.md rename to exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md diff --git a/exercises/concept/namespaces/.meta/Example.cs b/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs similarity index 100% rename from exercises/concept/namespaces/.meta/Example.cs rename to exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/config.json b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json new file mode 100644 index 0000000000..74b4c034b6 --- /dev/null +++ b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["RedVsBlueDarwinStyle.cs"], + "test_files": ["RedVsBlueDarwinStyleTests.cs"] + } +} diff --git a/exercises/concept/namespaces/.meta/design.md b/exercises/concept/red-vs-blue-darwin-style/.meta/design.md similarity index 100% rename from exercises/concept/namespaces/.meta/design.md rename to exercises/concept/red-vs-blue-darwin-style/.meta/design.md diff --git a/exercises/concept/namespaces/Namespaces.cs b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs similarity index 100% rename from exercises/concept/namespaces/Namespaces.cs rename to exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs diff --git a/exercises/concept/regular-expressions/RegularExpressions.csproj b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj similarity index 100% rename from exercises/concept/regular-expressions/RegularExpressions.csproj rename to exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj diff --git a/exercises/concept/namespaces/NamespacesTests.cs b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs similarity index 100% rename from exercises/concept/namespaces/NamespacesTests.cs rename to exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs diff --git a/exercises/concept/regular-expressions/.meta/config.json b/exercises/concept/regular-expressions/.meta/config.json deleted file mode 100644 index 517585e9b9..0000000000 --- a/exercises/concept/regular-expressions/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Regular-expressions.cs"], - "test_files": ["Regular-expressionsTests.cs"] - } -} diff --git a/exercises/concept/nested-types/.docs/hints.md b/exercises/concept/remote-control-cleanup/.docs/hints.md similarity index 100% rename from exercises/concept/nested-types/.docs/hints.md rename to exercises/concept/remote-control-cleanup/.docs/hints.md diff --git a/exercises/concept/nested-types/.docs/instructions.md b/exercises/concept/remote-control-cleanup/.docs/instructions.md similarity index 100% rename from exercises/concept/nested-types/.docs/instructions.md rename to exercises/concept/remote-control-cleanup/.docs/instructions.md diff --git a/exercises/concept/nested-types/.docs/introduction.md b/exercises/concept/remote-control-cleanup/.docs/introduction.md similarity index 100% rename from exercises/concept/nested-types/.docs/introduction.md rename to exercises/concept/remote-control-cleanup/.docs/introduction.md diff --git a/exercises/concept/nested-types/.meta/Example.cs b/exercises/concept/remote-control-cleanup/.meta/Example.cs similarity index 100% rename from exercises/concept/nested-types/.meta/Example.cs rename to exercises/concept/remote-control-cleanup/.meta/Example.cs diff --git a/exercises/concept/remote-control-cleanup/.meta/config.json b/exercises/concept/remote-control-cleanup/.meta/config.json new file mode 100644 index 0000000000..be0ef37bb4 --- /dev/null +++ b/exercises/concept/remote-control-cleanup/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["RemoteControlCleanup.cs"], + "test_files": ["RemoteControlCleanupTests.cs"] + } +} diff --git a/exercises/concept/nested-types/.meta/design.md b/exercises/concept/remote-control-cleanup/.meta/design.md similarity index 100% rename from exercises/concept/nested-types/.meta/design.md rename to exercises/concept/remote-control-cleanup/.meta/design.md diff --git a/exercises/concept/nested-types/NestedTypes.cs b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.cs similarity index 100% rename from exercises/concept/nested-types/NestedTypes.cs rename to exercises/concept/remote-control-cleanup/RemoteControlCleanup.cs diff --git a/exercises/concept/resource-cleanup/ResourceCleanup.csproj b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj similarity index 100% rename from exercises/concept/resource-cleanup/ResourceCleanup.csproj rename to exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj diff --git a/exercises/concept/nested-types/NestedTypesTests.cs b/exercises/concept/remote-control-cleanup/RemoteControlCleanupTests.cs similarity index 100% rename from exercises/concept/nested-types/NestedTypesTests.cs rename to exercises/concept/remote-control-cleanup/RemoteControlCleanupTests.cs diff --git a/exercises/concept/interfaces/.docs/hints.md b/exercises/concept/remote-control-competition/.docs/hints.md similarity index 100% rename from exercises/concept/interfaces/.docs/hints.md rename to exercises/concept/remote-control-competition/.docs/hints.md diff --git a/exercises/concept/interfaces/.docs/instructions.md b/exercises/concept/remote-control-competition/.docs/instructions.md similarity index 100% rename from exercises/concept/interfaces/.docs/instructions.md rename to exercises/concept/remote-control-competition/.docs/instructions.md diff --git a/exercises/concept/interfaces/.docs/introduction.md b/exercises/concept/remote-control-competition/.docs/introduction.md similarity index 100% rename from exercises/concept/interfaces/.docs/introduction.md rename to exercises/concept/remote-control-competition/.docs/introduction.md diff --git a/exercises/concept/interfaces/.meta/Example.cs b/exercises/concept/remote-control-competition/.meta/Example.cs similarity index 100% rename from exercises/concept/interfaces/.meta/Example.cs rename to exercises/concept/remote-control-competition/.meta/Example.cs diff --git a/exercises/concept/interfaces/.meta/config.json b/exercises/concept/remote-control-competition/.meta/config.json similarity index 75% rename from exercises/concept/interfaces/.meta/config.json rename to exercises/concept/remote-control-competition/.meta/config.json index 31177a4e7d..4b9e9a526b 100644 --- a/exercises/concept/interfaces/.meta/config.json +++ b/exercises/concept/remote-control-competition/.meta/config.json @@ -16,7 +16,7 @@ } ], "editor": { - "solution_files": ["Interfaces.cs"], - "test_files": ["InterfacesTests.cs"] + "solution_files": ["RemoteControlCompetition.cs"], + "test_files": ["RemoteControlCompetitionTests.cs"] } } diff --git a/exercises/concept/interfaces/.meta/design.md b/exercises/concept/remote-control-competition/.meta/design.md similarity index 100% rename from exercises/concept/interfaces/.meta/design.md rename to exercises/concept/remote-control-competition/.meta/design.md diff --git a/exercises/concept/interfaces/Interfaces.cs b/exercises/concept/remote-control-competition/RemoteControlCompetition.cs similarity index 100% rename from exercises/concept/interfaces/Interfaces.cs rename to exercises/concept/remote-control-competition/RemoteControlCompetition.cs diff --git a/exercises/concept/resource-lifetime/ResourceLifetime.csproj b/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj similarity index 100% rename from exercises/concept/resource-lifetime/ResourceLifetime.csproj rename to exercises/concept/remote-control-competition/RemoteControlCompetition.csproj diff --git a/exercises/concept/interfaces/InterfacesTests.cs b/exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs similarity index 100% rename from exercises/concept/interfaces/InterfacesTests.cs rename to exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs diff --git a/exercises/concept/resource-cleanup/.meta/config.json b/exercises/concept/resource-cleanup/.meta/config.json deleted file mode 100644 index 2f8d1ac3f6..0000000000 --- a/exercises/concept/resource-cleanup/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Resource-cleanup.cs"], - "test_files": ["Resource-cleanupTests.cs"] - } -} diff --git a/exercises/concept/resource-lifetime/.meta/config.json b/exercises/concept/resource-lifetime/.meta/config.json deleted file mode 100644 index de0d690095..0000000000 --- a/exercises/concept/resource-lifetime/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Resource-lifetime.cs"], - "test_files": ["Resource-lifetimeTests.cs"] - } -} diff --git a/exercises/concept/randomness/.docs/hints.md b/exercises/concept/roll-the-die/.docs/hints.md similarity index 100% rename from exercises/concept/randomness/.docs/hints.md rename to exercises/concept/roll-the-die/.docs/hints.md diff --git a/exercises/concept/randomness/.docs/instructions.md b/exercises/concept/roll-the-die/.docs/instructions.md similarity index 100% rename from exercises/concept/randomness/.docs/instructions.md rename to exercises/concept/roll-the-die/.docs/instructions.md diff --git a/exercises/concept/randomness/.docs/introduction.md b/exercises/concept/roll-the-die/.docs/introduction.md similarity index 100% rename from exercises/concept/randomness/.docs/introduction.md rename to exercises/concept/roll-the-die/.docs/introduction.md diff --git a/exercises/concept/randomness/.meta/Example.cs b/exercises/concept/roll-the-die/.meta/Example.cs similarity index 100% rename from exercises/concept/randomness/.meta/Example.cs rename to exercises/concept/roll-the-die/.meta/Example.cs diff --git a/exercises/concept/equality/.meta/config.json b/exercises/concept/roll-the-die/.meta/config.json similarity index 75% rename from exercises/concept/equality/.meta/config.json rename to exercises/concept/roll-the-die/.meta/config.json index e5517796d9..205728592c 100644 --- a/exercises/concept/equality/.meta/config.json +++ b/exercises/concept/roll-the-die/.meta/config.json @@ -12,7 +12,7 @@ } ], "editor": { - "solution_files": ["Equality.cs"], - "test_files": ["EqualityTests.cs"] + "solution_files": ["RollTheDie.cs"], + "test_files": ["RollTheDieTests.cs"] } } diff --git a/exercises/concept/randomness/.meta/design.md b/exercises/concept/roll-the-die/.meta/design.md similarity index 100% rename from exercises/concept/randomness/.meta/design.md rename to exercises/concept/roll-the-die/.meta/design.md diff --git a/exercises/concept/randomness/Randomness.cs b/exercises/concept/roll-the-die/RollTheDie.cs similarity index 100% rename from exercises/concept/randomness/Randomness.cs rename to exercises/concept/roll-the-die/RollTheDie.cs diff --git a/exercises/concept/randomness/Randomness.csproj b/exercises/concept/roll-the-die/RollTheDie.csproj similarity index 100% rename from exercises/concept/randomness/Randomness.csproj rename to exercises/concept/roll-the-die/RollTheDie.csproj diff --git a/exercises/concept/randomness/RandomnessTests.cs b/exercises/concept/roll-the-die/RollTheDieTests.cs similarity index 100% rename from exercises/concept/randomness/RandomnessTests.cs rename to exercises/concept/roll-the-die/RollTheDieTests.cs diff --git a/exercises/concept/casting/.docs/hints.md b/exercises/concept/secure-munchester-united/.docs/hints.md similarity index 100% rename from exercises/concept/casting/.docs/hints.md rename to exercises/concept/secure-munchester-united/.docs/hints.md diff --git a/exercises/concept/casting/.docs/instructions.md b/exercises/concept/secure-munchester-united/.docs/instructions.md similarity index 100% rename from exercises/concept/casting/.docs/instructions.md rename to exercises/concept/secure-munchester-united/.docs/instructions.md diff --git a/exercises/concept/casting/.docs/introduction.md b/exercises/concept/secure-munchester-united/.docs/introduction.md similarity index 100% rename from exercises/concept/casting/.docs/introduction.md rename to exercises/concept/secure-munchester-united/.docs/introduction.md diff --git a/exercises/concept/casting/.meta/Example.cs b/exercises/concept/secure-munchester-united/.meta/Example.cs similarity index 100% rename from exercises/concept/casting/.meta/Example.cs rename to exercises/concept/secure-munchester-united/.meta/Example.cs diff --git a/exercises/concept/secure-munchester-united/.meta/config.json b/exercises/concept/secure-munchester-united/.meta/config.json new file mode 100644 index 0000000000..bf3ee251d0 --- /dev/null +++ b/exercises/concept/secure-munchester-united/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["SecureMunchesterUnited.cs"], + "test_files": ["SecureMunchesterUnitedTests.cs"] + } +} diff --git a/exercises/concept/casting/.meta/design.md b/exercises/concept/secure-munchester-united/.meta/design.md similarity index 100% rename from exercises/concept/casting/.meta/design.md rename to exercises/concept/secure-munchester-united/.meta/design.md diff --git a/exercises/concept/casting/Casting.cs b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs similarity index 100% rename from exercises/concept/casting/Casting.cs rename to exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs diff --git a/exercises/concept/string-formatting/StringFormatting.csproj b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj similarity index 100% rename from exercises/concept/string-formatting/StringFormatting.csproj rename to exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj diff --git a/exercises/concept/casting/CastingTests.cs b/exercises/concept/secure-munchester-united/SecureMunchesterUnitedTests.cs similarity index 100% rename from exercises/concept/casting/CastingTests.cs rename to exercises/concept/secure-munchester-united/SecureMunchesterUnitedTests.cs diff --git a/exercises/concept/chars/.docs/hints.md b/exercises/concept/squeaky-clean/.docs/hints.md similarity index 100% rename from exercises/concept/chars/.docs/hints.md rename to exercises/concept/squeaky-clean/.docs/hints.md diff --git a/exercises/concept/chars/.docs/instructions.md b/exercises/concept/squeaky-clean/.docs/instructions.md similarity index 100% rename from exercises/concept/chars/.docs/instructions.md rename to exercises/concept/squeaky-clean/.docs/instructions.md diff --git a/exercises/concept/chars/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md similarity index 100% rename from exercises/concept/chars/.docs/introduction.md rename to exercises/concept/squeaky-clean/.docs/introduction.md diff --git a/exercises/concept/chars/.meta/Example.cs b/exercises/concept/squeaky-clean/.meta/Example.cs similarity index 100% rename from exercises/concept/chars/.meta/Example.cs rename to exercises/concept/squeaky-clean/.meta/Example.cs diff --git a/exercises/concept/casting/.meta/config.json b/exercises/concept/squeaky-clean/.meta/config.json similarity index 74% rename from exercises/concept/casting/.meta/config.json rename to exercises/concept/squeaky-clean/.meta/config.json index 3aa646115b..da2d0ddd3d 100644 --- a/exercises/concept/casting/.meta/config.json +++ b/exercises/concept/squeaky-clean/.meta/config.json @@ -12,7 +12,7 @@ } ], "editor": { - "solution_files": ["Casting.cs"], - "test_files": ["CastingTests.cs"] + "solution_files": ["SqueakyClean.cs"], + "test_files": ["SqueakyCleanTests.cs"] } } diff --git a/exercises/concept/chars/.meta/design.md b/exercises/concept/squeaky-clean/.meta/design.md similarity index 100% rename from exercises/concept/chars/.meta/design.md rename to exercises/concept/squeaky-clean/.meta/design.md diff --git a/exercises/concept/chars/Chars.cs b/exercises/concept/squeaky-clean/SqueakyClean.cs similarity index 100% rename from exercises/concept/chars/Chars.cs rename to exercises/concept/squeaky-clean/SqueakyClean.cs diff --git a/exercises/concept/structs/Structs.csproj b/exercises/concept/squeaky-clean/SqueakyClean.csproj similarity index 100% rename from exercises/concept/structs/Structs.csproj rename to exercises/concept/squeaky-clean/SqueakyClean.csproj diff --git a/exercises/concept/chars/CharsTests.cs b/exercises/concept/squeaky-clean/SqueakyCleanTests.cs similarity index 100% rename from exercises/concept/chars/CharsTests.cs rename to exercises/concept/squeaky-clean/SqueakyCleanTests.cs diff --git a/exercises/concept/strings/.meta/config.json b/exercises/concept/strings/.meta/config.json deleted file mode 100644 index c938b01f22..0000000000 --- a/exercises/concept/strings/.meta/config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "editor": { - "solution_files": ["Strings.cs"], - "test_files": ["StringsTests.cs"] - } -} diff --git a/exercises/concept/expression-bodied-members/.docs/hints.md b/exercises/concept/the-weather-in-deather/.docs/hints.md similarity index 100% rename from exercises/concept/expression-bodied-members/.docs/hints.md rename to exercises/concept/the-weather-in-deather/.docs/hints.md diff --git a/exercises/concept/expression-bodied-members/.docs/instructions.md b/exercises/concept/the-weather-in-deather/.docs/instructions.md similarity index 100% rename from exercises/concept/expression-bodied-members/.docs/instructions.md rename to exercises/concept/the-weather-in-deather/.docs/instructions.md diff --git a/exercises/concept/expression-bodied-members/.docs/introduction.md b/exercises/concept/the-weather-in-deather/.docs/introduction.md similarity index 100% rename from exercises/concept/expression-bodied-members/.docs/introduction.md rename to exercises/concept/the-weather-in-deather/.docs/introduction.md diff --git a/exercises/concept/expression-bodied-members/.meta/Example.cs b/exercises/concept/the-weather-in-deather/.meta/Example.cs similarity index 100% rename from exercises/concept/expression-bodied-members/.meta/Example.cs rename to exercises/concept/the-weather-in-deather/.meta/Example.cs diff --git a/exercises/concept/the-weather-in-deather/.meta/config.json b/exercises/concept/the-weather-in-deather/.meta/config.json new file mode 100644 index 0000000000..fc9c5aa1f8 --- /dev/null +++ b/exercises/concept/the-weather-in-deather/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["TheWeatherInDeather.cs"], + "test_files": ["TheWeatherInDeatherTests.cs"] + } +} diff --git a/exercises/concept/expression-bodied-members/.meta/design.md b/exercises/concept/the-weather-in-deather/.meta/design.md similarity index 100% rename from exercises/concept/expression-bodied-members/.meta/design.md rename to exercises/concept/the-weather-in-deather/.meta/design.md diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.cs similarity index 100% rename from exercises/concept/expression-bodied-members/ExpressionBodiedMembers.cs rename to exercises/concept/the-weather-in-deather/TheWeatherInDeather.cs diff --git a/exercises/concept/switch-statements/SwitchStatements.csproj b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj similarity index 100% rename from exercises/concept/switch-statements/SwitchStatements.csproj rename to exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj diff --git a/exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs b/exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs similarity index 100% rename from exercises/concept/expression-bodied-members/ExpressionBodiedMembersTests.cs rename to exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs diff --git a/exercises/concept/nullability/.docs/hints.md b/exercises/concept/tim-from-marketing/.docs/hints.md similarity index 100% rename from exercises/concept/nullability/.docs/hints.md rename to exercises/concept/tim-from-marketing/.docs/hints.md diff --git a/exercises/concept/nullability/.docs/instructions.md b/exercises/concept/tim-from-marketing/.docs/instructions.md similarity index 100% rename from exercises/concept/nullability/.docs/instructions.md rename to exercises/concept/tim-from-marketing/.docs/instructions.md diff --git a/exercises/concept/nullability/.docs/introduction.md b/exercises/concept/tim-from-marketing/.docs/introduction.md similarity index 100% rename from exercises/concept/nullability/.docs/introduction.md rename to exercises/concept/tim-from-marketing/.docs/introduction.md diff --git a/exercises/concept/nullability/.meta/Example.cs b/exercises/concept/tim-from-marketing/.meta/Example.cs similarity index 100% rename from exercises/concept/nullability/.meta/Example.cs rename to exercises/concept/tim-from-marketing/.meta/Example.cs diff --git a/exercises/concept/nullability/.meta/config.json b/exercises/concept/tim-from-marketing/.meta/config.json similarity index 59% rename from exercises/concept/nullability/.meta/config.json rename to exercises/concept/tim-from-marketing/.meta/config.json index a8d827340c..ecf6fb2acd 100644 --- a/exercises/concept/nullability/.meta/config.json +++ b/exercises/concept/tim-from-marketing/.meta/config.json @@ -6,7 +6,7 @@ } ], "editor": { - "solution_files": ["Nullability.cs"], - "test_files": ["NullabilityTests.cs"] + "solution_files": ["TimFromMarketing.cs"], + "test_files": ["TimFromMarketingTests.cs"] } } diff --git a/exercises/concept/nullability/.meta/design.md b/exercises/concept/tim-from-marketing/.meta/design.md similarity index 100% rename from exercises/concept/nullability/.meta/design.md rename to exercises/concept/tim-from-marketing/.meta/design.md diff --git a/exercises/concept/nullability/Nullability.cs b/exercises/concept/tim-from-marketing/TimFromMarketing.cs similarity index 100% rename from exercises/concept/nullability/Nullability.cs rename to exercises/concept/tim-from-marketing/TimFromMarketing.cs diff --git a/exercises/concept/nullability/Nullability.csproj b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj similarity index 100% rename from exercises/concept/nullability/Nullability.csproj rename to exercises/concept/tim-from-marketing/TimFromMarketing.csproj diff --git a/exercises/concept/nullability/NullabilityTests.cs b/exercises/concept/tim-from-marketing/TimFromMarketingTests.cs similarity index 100% rename from exercises/concept/nullability/NullabilityTests.cs rename to exercises/concept/tim-from-marketing/TimFromMarketingTests.cs diff --git a/exercises/concept/time/.meta/config.json b/exercises/concept/time/.meta/config.json deleted file mode 100644 index 8584711c77..0000000000 --- a/exercises/concept/time/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Time.cs"], - "test_files": ["TimeTests.cs"] - } -} diff --git a/exercises/concept/lists/.docs/hints.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md similarity index 100% rename from exercises/concept/lists/.docs/hints.md rename to exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md diff --git a/exercises/concept/lists/.docs/instructions.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md similarity index 100% rename from exercises/concept/lists/.docs/instructions.md rename to exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md diff --git a/exercises/concept/lists/.docs/introduction.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md similarity index 100% rename from exercises/concept/lists/.docs/introduction.md rename to exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md diff --git a/exercises/concept/lists/.meta/Example.cs b/exercises/concept/tracks-on-tracks-on-tracks/.meta/Example.cs similarity index 100% rename from exercises/concept/lists/.meta/Example.cs rename to exercises/concept/tracks-on-tracks-on-tracks/.meta/Example.cs diff --git a/exercises/concept/lists/.meta/config.json b/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json similarity index 73% rename from exercises/concept/lists/.meta/config.json rename to exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json index fa8143ecf7..35e32ebd6b 100644 --- a/exercises/concept/lists/.meta/config.json +++ b/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json @@ -13,7 +13,7 @@ ], "forked_from": ["fsharp/lists"], "editor": { - "solution_files": ["Lists.cs"], - "test_files": ["ListsTests.cs"] + "solution_files": ["TracksOnTracksOnTracks.cs"], + "test_files": ["TracksOnTracksOnTracksTests.cs"] } } diff --git a/exercises/concept/lists/.meta/design.md b/exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md similarity index 100% rename from exercises/concept/lists/.meta/design.md rename to exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md diff --git a/exercises/concept/lists/Lists.cs b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.cs similarity index 100% rename from exercises/concept/lists/Lists.cs rename to exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.cs diff --git a/exercises/concept/time/Time.csproj b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj similarity index 100% rename from exercises/concept/time/Time.csproj rename to exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj diff --git a/exercises/concept/lists/ListsTests.cs b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracksTests.cs similarity index 100% rename from exercises/concept/lists/ListsTests.cs rename to exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracksTests.cs diff --git a/exercises/concept/tuples/.meta/config.json b/exercises/concept/tuples/.meta/config.json deleted file mode 100644 index e18ab16029..0000000000 --- a/exercises/concept/tuples/.meta/config.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "contributors": [ - { - "github_username": "ErikSchierboom", - "exercism_username": "ErikSchierboom" - } - ], - "authors": [ - { - "github_username": "mikedamay", - "exercism_username": "mikedamay" - } - ], - "editor": { - "solution_files": ["Tuples.cs"], - "test_files": ["TuplesTests.cs"] - } -} diff --git a/exercises/concept/properties/.docs/hints.md b/exercises/concept/weighing-machine/.docs/hints.md similarity index 100% rename from exercises/concept/properties/.docs/hints.md rename to exercises/concept/weighing-machine/.docs/hints.md diff --git a/exercises/concept/properties/.docs/instructions.md b/exercises/concept/weighing-machine/.docs/instructions.md similarity index 100% rename from exercises/concept/properties/.docs/instructions.md rename to exercises/concept/weighing-machine/.docs/instructions.md diff --git a/exercises/concept/properties/.docs/introduction.md b/exercises/concept/weighing-machine/.docs/introduction.md similarity index 100% rename from exercises/concept/properties/.docs/introduction.md rename to exercises/concept/weighing-machine/.docs/introduction.md diff --git a/exercises/concept/properties/.meta/Example.cs b/exercises/concept/weighing-machine/.meta/Example.cs similarity index 100% rename from exercises/concept/properties/.meta/Example.cs rename to exercises/concept/weighing-machine/.meta/Example.cs diff --git a/exercises/concept/weighing-machine/.meta/config.json b/exercises/concept/weighing-machine/.meta/config.json new file mode 100644 index 0000000000..7228268a50 --- /dev/null +++ b/exercises/concept/weighing-machine/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["WeighingMachine.cs"], + "test_files": ["WeighingMachineTests.cs"] + } +} diff --git a/exercises/concept/properties/.meta/design.md b/exercises/concept/weighing-machine/.meta/design.md similarity index 94% rename from exercises/concept/properties/.meta/design.md rename to exercises/concept/weighing-machine/.meta/design.md index ae4dc986bc..afb1ab6f44 100644 --- a/exercises/concept/properties/.meta/design.md +++ b/exercises/concept/weighing-machine/.meta/design.md @@ -207,16 +207,16 @@ When implementing this exericse, it can be very useful to look at already implem [csharp-docs]: https://github.com/exercism/v3/blob/master/languages/csharp/README.md [csharp-docs-concept-exercises-strings]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/strings [csharp-docs-concept-exercises-datetimes]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/dates -[csharp-docs-concept-exercises-numbers-floating-point]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/floating-point-numbers +[csharp-docs-concept-exercises-numbers-floating-point]: https://github.com/exercism/v3/tree/master/interest-is-interesting [csharp-analyzer]: https://github.com/exercism/csharp-analyzer [csharp-representer]: https://github.com/exercism/csharp-representer [csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md [csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md -[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/after.md -[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/hints.md -[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/introduction.md -[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/instructions.md -[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.docs/design.md -[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/concept/floating-point-numbers/.meta/config.json +[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/after.md +[csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/hints.md +[csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/introduction.md +[csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/instructions.md +[csharp-docs-design.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/design.md +[csharp-meta-config.json]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.meta/config.json [csharp-docs-concept-exercises]: https://github.com/exercism/v3/tree/master/languages/csharp/exercises/concept/README.md [referrence-array]: https://github.com/exercism/v3/blob/master/reference/types/array.md diff --git a/exercises/concept/properties/Properties.cs b/exercises/concept/weighing-machine/WeighingMachine.cs similarity index 100% rename from exercises/concept/properties/Properties.cs rename to exercises/concept/weighing-machine/WeighingMachine.cs diff --git a/exercises/concept/properties/Properties.csproj b/exercises/concept/weighing-machine/WeighingMachine.csproj similarity index 100% rename from exercises/concept/properties/Properties.csproj rename to exercises/concept/weighing-machine/WeighingMachine.csproj diff --git a/exercises/concept/properties/PropertiesTests.cs b/exercises/concept/weighing-machine/WeighingMachineTests.cs similarity index 100% rename from exercises/concept/properties/PropertiesTests.cs rename to exercises/concept/weighing-machine/WeighingMachineTests.cs diff --git a/exercises/concept/object-initializers/.docs/hints.md b/exercises/concept/why-cant-i-push-to-main/.docs/hints.md similarity index 100% rename from exercises/concept/object-initializers/.docs/hints.md rename to exercises/concept/why-cant-i-push-to-main/.docs/hints.md diff --git a/exercises/concept/object-initializers/.docs/instructions.md b/exercises/concept/why-cant-i-push-to-main/.docs/instructions.md similarity index 100% rename from exercises/concept/object-initializers/.docs/instructions.md rename to exercises/concept/why-cant-i-push-to-main/.docs/instructions.md diff --git a/exercises/concept/object-initializers/.docs/introduction.md b/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md similarity index 100% rename from exercises/concept/object-initializers/.docs/introduction.md rename to exercises/concept/why-cant-i-push-to-main/.docs/introduction.md diff --git a/exercises/concept/object-initializers/.meta/Example.cs b/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs similarity index 100% rename from exercises/concept/object-initializers/.meta/Example.cs rename to exercises/concept/why-cant-i-push-to-main/.meta/Example.cs diff --git a/exercises/concept/why-cant-i-push-to-main/.meta/config.json b/exercises/concept/why-cant-i-push-to-main/.meta/config.json new file mode 100644 index 0000000000..a9d5b8209e --- /dev/null +++ b/exercises/concept/why-cant-i-push-to-main/.meta/config.json @@ -0,0 +1,18 @@ +{ + "contributors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "authors": [ + { + "github_username": "mikedamay", + "exercism_username": "mikedamay" + } + ], + "editor": { + "solution_files": ["WhyCantIPushToMain.cs"], + "test_files": ["WhyCantIPushToMainTests.cs"] + } +} diff --git a/exercises/concept/object-initializers/.meta/design.md b/exercises/concept/why-cant-i-push-to-main/.meta/design.md similarity index 100% rename from exercises/concept/object-initializers/.meta/design.md rename to exercises/concept/why-cant-i-push-to-main/.meta/design.md diff --git a/exercises/concept/object-initializers/ObjectInitialization.cs b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.cs similarity index 100% rename from exercises/concept/object-initializers/ObjectInitialization.cs rename to exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.cs diff --git a/exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj similarity index 100% rename from exercises/concept/user-defined-exceptions/UserDefinedExceptions.csproj rename to exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj diff --git a/exercises/concept/object-initializers/ObjectInitializationTests.cs b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMainTests.cs similarity index 100% rename from exercises/concept/object-initializers/ObjectInitializationTests.cs rename to exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMainTests.cs diff --git a/exercises/concept/method-overloading/.docs/hints.md b/exercises/concept/wizards-and-warriors-2/.docs/hints.md similarity index 100% rename from exercises/concept/method-overloading/.docs/hints.md rename to exercises/concept/wizards-and-warriors-2/.docs/hints.md diff --git a/exercises/concept/method-overloading/.docs/instructions.md b/exercises/concept/wizards-and-warriors-2/.docs/instructions.md similarity index 100% rename from exercises/concept/method-overloading/.docs/instructions.md rename to exercises/concept/wizards-and-warriors-2/.docs/instructions.md diff --git a/exercises/concept/method-overloading/.docs/introduction.md b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md similarity index 100% rename from exercises/concept/method-overloading/.docs/introduction.md rename to exercises/concept/wizards-and-warriors-2/.docs/introduction.md diff --git a/exercises/concept/method-overloading/.meta/Example.cs b/exercises/concept/wizards-and-warriors-2/.meta/Example.cs similarity index 100% rename from exercises/concept/method-overloading/.meta/Example.cs rename to exercises/concept/wizards-and-warriors-2/.meta/Example.cs diff --git a/exercises/concept/wizards-and-warriors-2/.meta/config.json b/exercises/concept/wizards-and-warriors-2/.meta/config.json new file mode 100644 index 0000000000..aad840f568 --- /dev/null +++ b/exercises/concept/wizards-and-warriors-2/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["WizardsAndWarriors2.cs"], + "test_files": ["WizardsAndWarriors2Tests.cs"] + } +} diff --git a/exercises/concept/method-overloading/.meta/design.md b/exercises/concept/wizards-and-warriors-2/.meta/design.md similarity index 100% rename from exercises/concept/method-overloading/.meta/design.md rename to exercises/concept/wizards-and-warriors-2/.meta/design.md diff --git a/exercises/concept/method-overloading/MethodOverloading.cs b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.cs similarity index 100% rename from exercises/concept/method-overloading/MethodOverloading.cs rename to exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.cs diff --git a/exercises/concept/numbers/Numbers.csproj b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj similarity index 100% rename from exercises/concept/numbers/Numbers.csproj rename to exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj diff --git a/exercises/concept/method-overloading/MethodOverloadingTests.cs b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2Tests.cs similarity index 100% rename from exercises/concept/method-overloading/MethodOverloadingTests.cs rename to exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2Tests.cs diff --git a/exercises/concept/inheritance/.docs/hints.md b/exercises/concept/wizards-and-warriors/.docs/hints.md similarity index 100% rename from exercises/concept/inheritance/.docs/hints.md rename to exercises/concept/wizards-and-warriors/.docs/hints.md diff --git a/exercises/concept/inheritance/.docs/instructions.md b/exercises/concept/wizards-and-warriors/.docs/instructions.md similarity index 100% rename from exercises/concept/inheritance/.docs/instructions.md rename to exercises/concept/wizards-and-warriors/.docs/instructions.md diff --git a/exercises/concept/inheritance/.docs/introduction.md b/exercises/concept/wizards-and-warriors/.docs/introduction.md similarity index 100% rename from exercises/concept/inheritance/.docs/introduction.md rename to exercises/concept/wizards-and-warriors/.docs/introduction.md diff --git a/exercises/concept/inheritance/.meta/Example.cs b/exercises/concept/wizards-and-warriors/.meta/Example.cs similarity index 100% rename from exercises/concept/inheritance/.meta/Example.cs rename to exercises/concept/wizards-and-warriors/.meta/Example.cs diff --git a/exercises/concept/wizards-and-warriors/.meta/config.json b/exercises/concept/wizards-and-warriors/.meta/config.json new file mode 100644 index 0000000000..b1d36e5d3f --- /dev/null +++ b/exercises/concept/wizards-and-warriors/.meta/config.json @@ -0,0 +1,12 @@ +{ + "authors": [ + { + "github_username": "ErikSchierboom", + "exercism_username": "ErikSchierboom" + } + ], + "editor": { + "solution_files": ["WizardsAndWarriors.cs"], + "test_files": ["WizardsAndWarriorsTests.cs"] + } +} diff --git a/exercises/concept/inheritance/.meta/design.md b/exercises/concept/wizards-and-warriors/.meta/design.md similarity index 100% rename from exercises/concept/inheritance/.meta/design.md rename to exercises/concept/wizards-and-warriors/.meta/design.md diff --git a/exercises/concept/inheritance/Inheritance.cs b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.cs similarity index 100% rename from exercises/concept/inheritance/Inheritance.cs rename to exercises/concept/wizards-and-warriors/WizardsAndWarriors.cs diff --git a/exercises/concept/strings/Strings.csproj b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj similarity index 100% rename from exercises/concept/strings/Strings.csproj rename to exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj diff --git a/exercises/concept/inheritance/InheritanceTests.cs b/exercises/concept/wizards-and-warriors/WizardsAndWarriorsTests.cs similarity index 100% rename from exercises/concept/inheritance/InheritanceTests.cs rename to exercises/concept/wizards-and-warriors/WizardsAndWarriorsTests.cs diff --git a/reference/exercises.json b/reference/exercises.json index 524d3f76b5..2f1ed7b353 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -12,7 +12,7 @@ ], "exercises": [ { - "slug": "classes", + "slug": "elons-toys", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -90,7 +90,7 @@ ] }, { - "slug": "inheritance", + "slug": "wizards-and-warriors", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -118,7 +118,7 @@ ] }, { - "slug": "basics", + "slug": "lucians-luscious-lasagna", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -206,7 +206,7 @@ ] }, { - "slug": "constructors", + "slug": "need-for-speed", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -224,7 +224,7 @@ ] }, { - "slug": "method-overloading", + "slug": "wizards-and-warriors-2", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -257,7 +257,7 @@ ] }, { - "slug": "properties", + "slug": "weighing-machine", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -275,7 +275,7 @@ ] }, { - "slug": "nullability", + "slug": "tim-from-marketing", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -333,7 +333,7 @@ ] }, { - "slug": "numbers", + "slug": "cars-assemble", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -395,7 +395,7 @@ ] }, { - "slug": "booleans", + "slug": "annalyns-infiltration", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -423,7 +423,7 @@ ] }, { - "slug": "chars", + "slug": "squeaky-clean", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -451,7 +451,7 @@ ] }, { - "slug": "arrays", + "slug": "bird-watcher", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -489,7 +489,7 @@ ] }, { - "slug": "dictionaries", + "slug": "international-calling-connoisseur", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -517,7 +517,7 @@ ] }, { - "slug": "datetimes", + "slug": "booking-up-for-beauty", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -535,7 +535,7 @@ ] }, { - "slug": "enums", + "slug": "logs-logs-logs", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -558,7 +558,7 @@ ] }, { - "slug": "floating-point-numbers", + "slug": "interest-is-interesting", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -596,7 +596,7 @@ ] }, { - "slug": "strings", + "slug": "log-levels", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -614,7 +614,7 @@ ] }, { - "slug": "flag-enums", + "slug": "attack-of-the-trolls", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -642,7 +642,7 @@ ] }, { - "slug": "user-defined-exceptions", + "slug": "instruments-of-texas", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -665,7 +665,7 @@ ] }, { - "slug": "equality", + "slug": "faceid-2", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -703,7 +703,7 @@ ] }, { - "slug": "tuples", + "slug": "phone-number-analysis", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -721,7 +721,7 @@ ] }, { - "slug": "randomness", + "slug": "roll-the-die", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -739,7 +739,7 @@ ] }, { - "slug": "parameters", + "slug": "building-telemetry", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -777,7 +777,7 @@ ] }, { - "slug": "switch-statements", + "slug": "football-match-reports", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -795,7 +795,7 @@ ] }, { - "slug": "object-initializers", + "slug": "why-cant-i-push-to-main", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -813,7 +813,7 @@ ] }, { - "slug": "resource-cleanup", + "slug": "object-relational-mapping", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -831,7 +831,7 @@ ] }, { - "slug": "time", + "slug": "beauty-salon-goes-global", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -864,7 +864,7 @@ ] }, { - "slug": "interfaces", + "slug": "remote-control-competition", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -902,7 +902,7 @@ ] }, { - "slug": "integral-numbers", + "slug": "hyper-optimized-telemetry", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -930,7 +930,7 @@ ] }, { - "slug": "constants", + "slug": "authentication-system", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -958,7 +958,7 @@ ] }, { - "slug": "exceptions", + "slug": "calculator-conundrum", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -976,7 +976,7 @@ ] }, { - "slug": "lists", + "slug": "tracks-on-tracks-on-tracks", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1014,7 +1014,7 @@ ] }, { - "slug": "structs", + "slug": "land-grab-in-space", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1032,7 +1032,7 @@ ] }, { - "slug": "expression-bodied-members", + "slug": "the-weather-in-deather", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1070,7 +1070,7 @@ ] }, { - "slug": "namespaces", + "slug": "red-vs-blue-darwin-style", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1103,7 +1103,7 @@ ] }, { - "slug": "string-formatting", + "slug": "high-school-sweethearts", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1141,7 +1141,7 @@ ] }, { - "slug": "regular-expressions", + "slug": "parsing-log-files", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1159,7 +1159,7 @@ ] }, { - "slug": "resource-lifetime", + "slug": "orm-in-one-go", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1177,7 +1177,7 @@ ] }, { - "slug": "overflow", + "slug": "hyperinflation-hits-hyperia", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1195,7 +1195,7 @@ ] }, { - "slug": "nested-types", + "slug": "remote-control-cleanup", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1213,7 +1213,7 @@ ] }, { - "slug": "casting", + "slug": "secure-munchester-united", "level": "introductory", "completion-status": "complete", "document-link": "", @@ -1241,7 +1241,7 @@ ] }, { - "slug": "operator-overloading", + "slug": "hyperia-forex", "level": "introductory", "completion-status": "complete", "document-link": "", diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 18ccce1af6..773d0c60c1 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -115,7 +115,7 @@ _Skip this step if you're not sure what to do._ ## Inspiration -When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [strings][concept-exercise-strings], [datetimes][concept-exercise-datetimes] or [floating-point numbers][concept-exercise-numbers-floating-point] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. +When implementing an exercise, it can be very useful to look at already implemented C# exercises like the [log-levels][concept-exercise-log-levels], [datetimes][concept-exercise-booking-up-for-beauty] or [floating-point numbers][concept-exercise-interest-is-interesting] exercises. You can also check the exercise's [general concepts documents][reference] to see if other languages have already implemented an exercise for that concept. ## Help @@ -129,9 +129,9 @@ If you have any questions regarding implementing the exercise, please post them [docs-rationale-for-v3]: ../../../docs/rationale-for-v3.md [docs-features-of-v3]: ../../../docs/features-of-v3.md [anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA -[concept-exercise-strings]: ../exercises/concept/strings -[concept-exercise-datetimes]: ../exercises/concept/datetimes -[concept-exercise-numbers-floating-point]: ../exercises/concept/floating-point-numbers +[concept-exercise-log-levels]: ../exercises/concept/log-levels +[concept-exercise-booking-up-for-beauty]: ../exercises/concept/booking-up-for-beauty +[concept-exercise-interest-is-interesting]: ../exercises/concept/interest-is-interesting [reference]: ../../../reference [dotnet-format]: https://github.com/dotnet/format [allowing-fork-pr-changes]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork @@ -139,23 +139,23 @@ If you have any questions regarding implementing the exercise, please post them [video-stub-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1171 [video-tests-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1255 [video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781 -[example-stub-file]: ../exercises/concept/strings/Strings.cs -[example-tests-file]: ../exercises/concept/strings/StringsTests.cs -[example-example-file]: ../exercises/concept/strings/.meta/Example.cs -[example-project-file]: ../exercises/concept/strings/Strings.csproj -[skip-fact]: ../exercises/concept/strings/StringsTests.cs#L11 -[test-name]: ../exercises/concept/strings/StringsTests.cs#L24 +[example-stub-file]: ../exercises/concept/log-levels/LogLevels.cs +[example-tests-file]: ../exercises/concept/log-levels/LogLevelsTests.cs +[example-example-file]: ../exercises/concept/log-levels/.meta/Example.cs +[example-project-file]: ../exercises/concept/log-levels/LogLevels.csproj +[skip-fact]: ../exercises/concept/log-levels/LogLevelsTests.cs#L11 +[test-name]: ../exercises/concept/log-levels/LogLevelsTests.cs#L24 [xunit]: https://xunit.net/ -[not-implemented-static]: ../exercises/concept/arrays/Arrays.cs#L12 -[not-implemented]: ../exercises/concept/arrays/Arrays.cs#L17 -[todo]: ../exercises/concept/basics/Basics.cs +[not-implemented-static]: ../exercises/concept/bird-watcher/BirdWatcher.cs#L12 +[not-implemented]: ../exercises/concept/bird-watcher/BirdWatcher.cs#L17 +[todo]: ../exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.cs [stub-file]: ../../../docs/concept-exercises.md#stub-implementation-file [tests-file]: ../../../docs/concept-exercises.md#tests-file [example-file]: ../../../docs/concept-exercises.md#example-implementation-file [video-stub-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1171 [video-tests-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1255 [video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781 -[example-stub-file]: ../languages/csharp/exercises/concept/strings/Strings.cs -[example-tests-file]: ../languages/csharp/exercises/concept/strings/StringsTests.cs -[example-example-file]: ../languages/csharp/exercises/concept/strings/.meta/Example.cs -[example-project-file]: ../exercises/concept/strings/Strings.csproj +[example-stub-file]: ../languages/csharp/exercises/concept/log-levels/LogLevels.cs +[example-tests-file]: ../languages/csharp/exercises/concept/log-levels/LogLevelsTests.cs +[example-example-file]: ../languages/csharp/exercises/concept/log-levels/.meta/Example.cs +[example-project-file]: ../exercises/concept/log-levels/LogLevels.csproj From 37d79712bc585375dcc7182530ebb43fb9eed075 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Nov 2020 10:14:40 +0100 Subject: [PATCH 258/327] Update exercise-report document Co-authored-by: github-actions[bot] --- reference/exercise-errors.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json index e3d71af596..6132a6a218 100644 --- a/reference/exercise-errors.json +++ b/reference/exercise-errors.json @@ -2,7 +2,7 @@ "Errors": [ { "Severity": "error", - "Message": "Failed to find concept compound-assignment, from the flag-enums design.md, in exercises.json file", + "Message": "Failed to find concept compound-assignment, from the attack-of-the-trolls design.md, in exercises.json file", "Source": "merge" } ] From 20befd88eb38f499e9ce666fc4f27f523b980690 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Thu, 5 Nov 2020 09:59:54 +0100 Subject: [PATCH 259/327] Add headings to introductions Add headings to introductions Co-authored-by: mikedamay --- .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 36 +++++++++++-------- .../.docs/introduction.md | 8 +++-- .../.docs/introduction.md | 4 +++ .../bird-watcher/.docs/introduction.md | 6 ++++ .../.docs/introduction.md | 2 ++ .../building-telemetry/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../cars-assemble/.docs/introduction.md | 4 +++ .../concept/elons-toys/.docs/introduction.md | 2 ++ .../concept/faceid-2/.docs/introduction.md | 6 ++-- .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 12 ++++--- .../.docs/introduction.md | 2 ++ .../hyperia-forex/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 4 ++- .../.docs/introduction.md | 19 ++++++++++ .../.docs/introduction.md | 2 ++ .../land-grab-in-space/.docs/introduction.md | 2 ++ .../concept/log-levels/.docs/introduction.md | 2 ++ .../logs-logs-logs/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../need-for-speed/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../orm-in-one-go/.docs/introduction.md | 2 ++ .../parsing-log-files/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 4 +++ .../roll-the-die/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../squeaky-clean/.docs/introduction.md | 4 +++ .../.docs/introduction.md | 8 +++-- .../tim-from-marketing/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 8 +++-- .../weighing-machine/.docs/introduction.md | 2 ++ .../.docs/introduction.md | 2 ++ .../.docs/introduction.md | 22 ++++++++++++ .../.docs/introduction.md | 2 ++ 41 files changed, 168 insertions(+), 31 deletions(-) diff --git a/exercises/concept/annalyns-infiltration/.docs/introduction.md b/exercises/concept/annalyns-infiltration/.docs/introduction.md index 5341d27350..fe13978ed3 100644 --- a/exercises/concept/annalyns-infiltration/.docs/introduction.md +++ b/exercises/concept/annalyns-infiltration/.docs/introduction.md @@ -1,3 +1,5 @@ +## booleans + Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`. C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR). diff --git a/exercises/concept/attack-of-the-trolls/.docs/introduction.md b/exercises/concept/attack-of-the-trolls/.docs/introduction.md index 2f383b1e22..4e9117a815 100644 --- a/exercises/concept/attack-of-the-trolls/.docs/introduction.md +++ b/exercises/concept/attack-of-the-trolls/.docs/introduction.md @@ -1,17 +1,4 @@ -The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the `Flags` attribute. A _flags_ enum's constants are interpreted as bitwise _flags_. - -A flags enum can be defined as follows (using binary integer notation): - -```csharp -[Flags] -enum PhoneFeatures -{ - Call = 0b00000001, - Text = 0b00000010 -} -``` - -A `PhoneFeatures` instance which value is `0b00000011` has both its `Call` _and_ `Text` flags set. +## bit-manipulation To work with bits, C# supports the following operators: @@ -29,6 +16,23 @@ Here is an example how to use a bitwise operator: // => 4 ``` +## flag-enums + +The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the `Flags` attribute. A _flags_ enum's constants are interpreted as bitwise _flags_. + +A flags enum can be defined as follows (using binary integer notation): + +```csharp +[Flags] +enum PhoneFeatures +{ + Call = 0b00000001, + Text = 0b00000010 +} +``` + +A `PhoneFeatures` instance which value is `0b00000011` has both its `Call` _and_ `Text` flags set. + By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration: ```csharp @@ -39,3 +43,7 @@ enum PhoneFeatures : byte Text = 0b00000010 } ``` + +## compound-assignment + +TODO: consider what to put here - do this in conjunction with issue #2529 cleanup about.md files and approach detailed in csharp/concepts/bit-manipulation/about.md. diff --git a/exercises/concept/authentication-system/.docs/introduction.md b/exercises/concept/authentication-system/.docs/introduction.md index 9f526174a9..c9460e3739 100644 --- a/exercises/concept/authentication-system/.docs/introduction.md +++ b/exercises/concept/authentication-system/.docs/introduction.md @@ -1,3 +1,5 @@ +## constants + The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program. ```csharp @@ -17,9 +19,9 @@ public MyClass(int num) } ``` -#### Read-only collections +## readonly-collections -Although the `readonly` modifier prevents the value or reference in a field from being overwritten, the modifier provides no protection for the members of a reference type. +While the `readonly` modifier prevents the value or reference in a field from being overwritten, it offers no protection for the members of a reference type. ```csharp readonly List ints = new List(); @@ -38,6 +40,6 @@ The Base Class Library (BCL) provides some readonly versions of collections wher - `ReadOnlyDictionary` exposes a `Dictionary` as read-only. - `ReadOnlyCollection` exposes a `List` as read-only. -#### Defensive copying +## defensive-copying In security sensitive situations (or even simply on a large code-base where developers have different priorities and agendas) you should avoid allowing a class's public API to be circumvented by accepting and storing a method's mutable parameters or by exposing a mutable member of a class through a return value or as an `out` parameter. diff --git a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md index b77d0d4e7e..8ea7c01e80 100644 --- a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md +++ b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md @@ -1,5 +1,9 @@ +## time + The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`. +## timezone + The `TimeZoneInfo` class provides routines for handling the differences between time zones. The `TimeZoneInfo` class also contains methods that facilitate dealing with daylight saving time. The `CultureInfo` class supports locale dependent date time formats. diff --git a/exercises/concept/bird-watcher/.docs/introduction.md b/exercises/concept/bird-watcher/.docs/introduction.md index b285eb638b..0dfe9b1a7c 100644 --- a/exercises/concept/bird-watcher/.docs/introduction.md +++ b/exercises/concept/bird-watcher/.docs/introduction.md @@ -1,3 +1,5 @@ +## arrays + In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero: ```csharp @@ -22,6 +24,8 @@ int[] threeIntsV3 = { 4, 9, 7 }; Arrays can be manipulated by either calling an array instance's methods or properties, or by using the static methods defined in the `Array` class. +## foreach-loops + The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over _all_ its values using a `foreach` loop: ```csharp @@ -36,6 +40,8 @@ foreach (char vowel in vowels) // => aeiou ``` +## for-loops + If you want more control over which values to iterate over, a `for` loop can be used: ```csharp diff --git a/exercises/concept/booking-up-for-beauty/.docs/introduction.md b/exercises/concept/booking-up-for-beauty/.docs/introduction.md index 7ba7a7786f..e369ed1483 100644 --- a/exercises/concept/booking-up-for-beauty/.docs/introduction.md +++ b/exercises/concept/booking-up-for-beauty/.docs/introduction.md @@ -1,3 +1,5 @@ +## datetimes + A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`. The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`. diff --git a/exercises/concept/building-telemetry/.docs/introduction.md b/exercises/concept/building-telemetry/.docs/introduction.md index 1c42283f86..c1a247b70c 100644 --- a/exercises/concept/building-telemetry/.docs/introduction.md +++ b/exercises/concept/building-telemetry/.docs/introduction.md @@ -1,3 +1,5 @@ +## parameters + This exercise discusses some details of method parameters and their use in C#. Parameters convey information from a calling method to a called method. diff --git a/exercises/concept/calculator-conundrum/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md index 20803e085a..4e91c760dd 100644 --- a/exercises/concept/calculator-conundrum/.docs/introduction.md +++ b/exercises/concept/calculator-conundrum/.docs/introduction.md @@ -1,3 +1,5 @@ +## exceptions + Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes. In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown. diff --git a/exercises/concept/cars-assemble/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md index 9b4bbf3aed..f695c2df7c 100644 --- a/exercises/concept/cars-assemble/.docs/introduction.md +++ b/exercises/concept/cars-assemble/.docs/introduction.md @@ -1,3 +1,5 @@ +## numbers + There are two different types of numbers in C#: - Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`. @@ -14,6 +16,8 @@ C# has two types of numeric conversions: As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion. +## if-statements + In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement: ```csharp diff --git a/exercises/concept/elons-toys/.docs/introduction.md b/exercises/concept/elons-toys/.docs/introduction.md index e3770a9229..51cd99cecd 100644 --- a/exercises/concept/elons-toys/.docs/introduction.md +++ b/exercises/concept/elons-toys/.docs/introduction.md @@ -1,3 +1,5 @@ +## classes + The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_. Access to members can be restricted through access modifiers, the two most common ones being: diff --git a/exercises/concept/faceid-2/.docs/introduction.md b/exercises/concept/faceid-2/.docs/introduction.md index 3642db959b..4061dd9f19 100644 --- a/exercises/concept/faceid-2/.docs/introduction.md +++ b/exercises/concept/faceid-2/.docs/introduction.md @@ -1,6 +1,4 @@ -This exercise looks at how you test for equality and the importance of hash codes. - -### `Object.Equals()` +## equality Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. @@ -22,6 +20,6 @@ The HashCode library API documentation discusses the best way to generate a hash The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be immutable. Other approaches run the risk of creating gotchas for maintainers. -### HashSet +## sets The `HashSet` library class provides a good mechanism for storing unique values. diff --git a/exercises/concept/football-match-reports/.docs/introduction.md b/exercises/concept/football-match-reports/.docs/introduction.md index 8395a6f1c9..d57cfbfa6d 100644 --- a/exercises/concept/football-match-reports/.docs/introduction.md +++ b/exercises/concept/football-match-reports/.docs/introduction.md @@ -1,3 +1,5 @@ +## switch-statements + Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program". The mechanism involves the following keywords: `switch`, `case`, `break` and `default`. diff --git a/exercises/concept/high-school-sweethearts/.docs/introduction.md b/exercises/concept/high-school-sweethearts/.docs/introduction.md index 7ab55730c9..d590a2369b 100644 --- a/exercises/concept/high-school-sweethearts/.docs/introduction.md +++ b/exercises/concept/high-school-sweethearts/.docs/introduction.md @@ -1,6 +1,8 @@ +## string-formatting + There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation. -## Composite Formatting +### Composite Formatting `String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as format items), and a variable number of arguments. The return value resolves each format item using the corresponding argument and combines the resolved values with the fixed text. @@ -11,7 +13,7 @@ string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, This mechanism is technically known as _composite formatting_. -## String Interpolation +### String Interpolation Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism. @@ -22,7 +24,7 @@ $"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password." // => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings ``` -## Format Items +### Format Items The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_. @@ -50,13 +52,13 @@ string.Format( There are both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format letters. -## Culture +### Culture Each thread has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_. `CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture. -## Verbatim Strings +## verbatim-strings Verbatim strings allow multi-line strings. They are introduced with an @. diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md index a134fd0930..2a86bc79da 100644 --- a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md +++ b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md @@ -1,3 +1,5 @@ +## integral-numbers + C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types. The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits. diff --git a/exercises/concept/hyperia-forex/.docs/introduction.md b/exercises/concept/hyperia-forex/.docs/introduction.md index 9c72dea800..4d09c2ef8d 100644 --- a/exercises/concept/hyperia-forex/.docs/introduction.md +++ b/exercises/concept/hyperia-forex/.docs/introduction.md @@ -1,3 +1,5 @@ +## operator-overloading + The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_. Most operators have the form: diff --git a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md index a2313bf95e..76fc34f288 100644 --- a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md +++ b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md @@ -1,3 +1,5 @@ +## overflow + Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type. Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances. diff --git a/exercises/concept/instruments-of-texas/.docs/introduction.md b/exercises/concept/instruments-of-texas/.docs/introduction.md index 9d60e65960..f304c84453 100644 --- a/exercises/concept/instruments-of-texas/.docs/introduction.md +++ b/exercises/concept/instruments-of-texas/.docs/introduction.md @@ -1,8 +1,10 @@ +## user-defined-exceptions + A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines. -## Exception Filters +## exception-filtering `when` is the key word in filtering exceptions. It is placed after the catch statement and can take a boolean expression containing any values in scope at the time. If the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked. diff --git a/exercises/concept/interest-is-interesting/.docs/introduction.md b/exercises/concept/interest-is-interesting/.docs/introduction.md index e9fb5e2b6d..1966481c64 100644 --- a/exercises/concept/interest-is-interesting/.docs/introduction.md +++ b/exercises/concept/interest-is-interesting/.docs/introduction.md @@ -1,3 +1,5 @@ +## floating-point-numbers + A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`. Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision. @@ -10,6 +12,8 @@ C# has three floating-point types: As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded). +## while-loops + In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here: ```csharp @@ -18,5 +22,20 @@ int x = 23; while (x > 10) { // Execute logic if x > 10 + x = x - 2; } ``` + +## do-while-loops + +An less commonly used alternative to the above syntax is a `do-while` loop: + +```csharp +int x = 23; + +do +{ + // Execute logic if x > 10 + x = x - 2; +} while (x > 10) +``` diff --git a/exercises/concept/international-calling-connoisseur/.docs/introduction.md b/exercises/concept/international-calling-connoisseur/.docs/introduction.md index 937cf345d3..82b2de31a5 100644 --- a/exercises/concept/international-calling-connoisseur/.docs/introduction.md +++ b/exercises/concept/international-calling-connoisseur/.docs/introduction.md @@ -1,3 +1,5 @@ +## dictionaries + A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages. A dictionary can be created as follows: diff --git a/exercises/concept/land-grab-in-space/.docs/introduction.md b/exercises/concept/land-grab-in-space/.docs/introduction.md index 6b1142d00f..f214c303f1 100644 --- a/exercises/concept/land-grab-in-space/.docs/introduction.md +++ b/exercises/concept/land-grab-in-space/.docs/introduction.md @@ -1,3 +1,5 @@ +## structs + C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections. ```csharp diff --git a/exercises/concept/log-levels/.docs/introduction.md b/exercises/concept/log-levels/.docs/introduction.md index d7d72cd2ec..2ededb0096 100644 --- a/exercises/concept/log-levels/.docs/introduction.md +++ b/exercises/concept/log-levels/.docs/introduction.md @@ -1,3 +1,5 @@ +## strings + A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance: ```csharp diff --git a/exercises/concept/logs-logs-logs/.docs/introduction.md b/exercises/concept/logs-logs-logs/.docs/introduction.md index 9f383a26bb..956e314c06 100644 --- a/exercises/concept/logs-logs-logs/.docs/introduction.md +++ b/exercises/concept/logs-logs-logs/.docs/introduction.md @@ -1,3 +1,5 @@ +## enums + The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows: ```csharp diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md index a0da40de82..f77dcbdc9f 100644 --- a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md +++ b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md @@ -1,3 +1,5 @@ +## basics + C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent: ```csharp diff --git a/exercises/concept/need-for-speed/.docs/introduction.md b/exercises/concept/need-for-speed/.docs/introduction.md index 1fbd17c9ef..f531f19eaa 100644 --- a/exercises/concept/need-for-speed/.docs/introduction.md +++ b/exercises/concept/need-for-speed/.docs/introduction.md @@ -1,3 +1,5 @@ +## constructors + Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name. ```csharp diff --git a/exercises/concept/object-relational-mapping/.docs/introduction.md b/exercises/concept/object-relational-mapping/.docs/introduction.md index ffeafbf696..0ef5a70fe6 100644 --- a/exercises/concept/object-relational-mapping/.docs/introduction.md +++ b/exercises/concept/object-relational-mapping/.docs/introduction.md @@ -1 +1,3 @@ +## resource-cleanup + If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset. diff --git a/exercises/concept/orm-in-one-go/.docs/introduction.md b/exercises/concept/orm-in-one-go/.docs/introduction.md index ee0bef510d..7850b02a3e 100644 --- a/exercises/concept/orm-in-one-go/.docs/introduction.md +++ b/exercises/concept/orm-in-one-go/.docs/introduction.md @@ -1,3 +1,5 @@ +## resource-lifetime + You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations. There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement. diff --git a/exercises/concept/parsing-log-files/.docs/introduction.md b/exercises/concept/parsing-log-files/.docs/introduction.md index 1256179199..d7d01daf72 100644 --- a/exercises/concept/parsing-log-files/.docs/introduction.md +++ b/exercises/concept/parsing-log-files/.docs/introduction.md @@ -1 +1,3 @@ +## regular-expressions + The .NET base class libraries provide the `Regex` class for processing of regular expressions. diff --git a/exercises/concept/phone-number-analysis/.docs/introduction.md b/exercises/concept/phone-number-analysis/.docs/introduction.md index 88510ef0c5..c81d436cf5 100644 --- a/exercises/concept/phone-number-analysis/.docs/introduction.md +++ b/exercises/concept/phone-number-analysis/.docs/introduction.md @@ -1,3 +1,5 @@ +## tuples + In C#, a tuple is a data structure which organizes data, holding two or more fields of any type. diff --git a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md index ccfd49113a..ea0abd4d3b 100644 --- a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md +++ b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md @@ -1,3 +1,5 @@ +## namespaces + Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base. The syntax is as follows: diff --git a/exercises/concept/remote-control-cleanup/.docs/introduction.md b/exercises/concept/remote-control-cleanup/.docs/introduction.md index 1edafdd14b..8ac8f8d2eb 100644 --- a/exercises/concept/remote-control-cleanup/.docs/introduction.md +++ b/exercises/concept/remote-control-cleanup/.docs/introduction.md @@ -1,3 +1,5 @@ +## nested-types + C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax. ```csharp diff --git a/exercises/concept/remote-control-competition/.docs/introduction.md b/exercises/concept/remote-control-competition/.docs/introduction.md index 85377201d0..2eea97a55b 100644 --- a/exercises/concept/remote-control-competition/.docs/introduction.md +++ b/exercises/concept/remote-control-competition/.docs/introduction.md @@ -1,3 +1,5 @@ +## interfaces + An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion. The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided. @@ -31,4 +33,6 @@ All operations defined by the interface must be implemented. Interfaces can contain instance methods and properties amongst other members +## ordering + The `IComparable` interface can be implemented where a default generic sort order in collections is required. diff --git a/exercises/concept/roll-the-die/.docs/introduction.md b/exercises/concept/roll-the-die/.docs/introduction.md index 264aec91ec..0aaffebbb6 100644 --- a/exercises/concept/roll-the-die/.docs/introduction.md +++ b/exercises/concept/roll-the-die/.docs/introduction.md @@ -1 +1,3 @@ +## randomness + In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case. diff --git a/exercises/concept/secure-munchester-united/.docs/introduction.md b/exercises/concept/secure-munchester-united/.docs/introduction.md index d05ff9408e..a739d842fe 100644 --- a/exercises/concept/secure-munchester-united/.docs/introduction.md +++ b/exercises/concept/secure-munchester-united/.docs/introduction.md @@ -1,3 +1,5 @@ +## casting + Casting and type conversion are different ways of changing an expression from one data type to another. An expression can be cast to another type with the cast operator `()`. diff --git a/exercises/concept/squeaky-clean/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md index c081632203..3b1e88f8e8 100644 --- a/exercises/concept/squeaky-clean/.docs/introduction.md +++ b/exercises/concept/squeaky-clean/.docs/introduction.md @@ -1,3 +1,5 @@ +## chars + The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text. Multiple `char`s can comprise a string such as `"word"` or `char`s can be processed independently. Their literals have single quotes e.g. `'A'`. @@ -9,6 +11,8 @@ e.g. ancient greek `'β'`. There are many builtin library methods to inspect and manipulate `char`s. These can be found as static methods of the `System.Char` class. +## string-builder + `char`s are sometimes used in conjunction with a `StringBuilder` object. This object has methods that allow a string to be constructed character by character and manipulated. At the end of the process diff --git a/exercises/concept/the-weather-in-deather/.docs/introduction.md b/exercises/concept/the-weather-in-deather/.docs/introduction.md index 425ebe588a..22b6561b76 100644 --- a/exercises/concept/the-weather-in-deather/.docs/introduction.md +++ b/exercises/concept/the-weather-in-deather/.docs/introduction.md @@ -1,3 +1,5 @@ +## expression-bodied-members + Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements. Methods and read-only properties are amongst the members that can be defined with expression bodies. @@ -8,7 +10,7 @@ public int Times3(int input) => input * 3; public int Interesting => 1729; ``` -#### Ternary operators +## ternary-operators Ternary operators allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone. @@ -20,13 +22,15 @@ int max = a > b ? a : b; // => 4 ``` +## throw-expressions + `throw` expressions are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions. ```csharp string trimmed = str == null ? throw new ArgumentException() : str.Trim(); ``` -#### Switch expressions +## switch-expressions A switch expression can match a value to one case in a set of patterns and return the associated value or take the associated action. The association is denoted by the `=>` symbol. In addition, each pattern can have an optional case guard introduced with the `when` keyword. The case guard expression must evaluate to true for that "arm" of the switch to be selected. The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found. diff --git a/exercises/concept/tim-from-marketing/.docs/introduction.md b/exercises/concept/tim-from-marketing/.docs/introduction.md index 6ce9868e2e..7c125eff5a 100644 --- a/exercises/concept/tim-from-marketing/.docs/introduction.md +++ b/exercises/concept/tim-from-marketing/.docs/introduction.md @@ -1,3 +1,5 @@ +## nullability + In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values. Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`). diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md index ccdfef907b..af3cae91da 100644 --- a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md +++ b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md @@ -1,4 +1,6 @@ -Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. `List` is generally referred to as a generic type and that `T` is the type parameter. +## lists + +Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists. Items can be added to and removed from lists. They grow and shrink as necessary. @@ -6,4 +8,6 @@ Items can be added to and removed from lists. They grow and shrink as necessary. var listOfStrings = new List(); ``` -A collection definition typically includes a place holder in angle brackets, often `T` by convention. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings. +## generic-types + +A collection definition typically includes a place holder in angle brackets, often `T` by convention. Such a collection is referred to as a generic type. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings. diff --git a/exercises/concept/weighing-machine/.docs/introduction.md b/exercises/concept/weighing-machine/.docs/introduction.md index 1405dddcca..eccdbea49a 100644 --- a/exercises/concept/weighing-machine/.docs/introduction.md +++ b/exercises/concept/weighing-machine/.docs/introduction.md @@ -1,3 +1,5 @@ +## properties + A property in C# is a member of a class that provides access to data within that class. Callers can set or retrieve (get) the data. Properties can be either auto-implemented or have a backing field. They comprise a set accessor and/or a get accessor. diff --git a/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md b/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md index 25b3b07ef5..e382ae4256 100644 --- a/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md +++ b/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md @@ -1,3 +1,5 @@ +## object-initializers + Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets: ```csharp diff --git a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md index c8ef7d9c81..0aa9b2a207 100644 --- a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md +++ b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md @@ -1,3 +1,5 @@ +## method-overloading + _Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either: - The number of parameters @@ -7,6 +9,8 @@ There is no method overloading based on the return type. The compiler will automatically infer which overloaded method to call based on the number of parameters and their type. +## optional-parameters + A method parameter can be made optional by assigning it a default value. When calling a method with optional parameters, the caller is not required to pass a value for them. If no value is passed for an optional parameter, its default value will be used. Optional parameters _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters. @@ -23,3 +27,21 @@ class Card Card.NewYear(); // => "Happy 2020!" Card.Card(1999); // => "Happy 1999!" ``` + +## named-arguments + +So far we have seen that the arguments passed into a method are matched to the method are matched to the method's declared parameters based on position. An alternative approach, particularly where a routine takes a large number of arguments, the caller can match arguments by specifying the declared parameter's identifier. + +The following illustrates the syntax: + +```csharp +class Card +{ + static string NewYear(int year, int month, int day) + { + return $"Happy {year}-{month}-{day}!"; + } +} + +Card.NewYear(month: 1, day: 1, year: 2020); // => "Happy 2020-1-1!" +``` diff --git a/exercises/concept/wizards-and-warriors/.docs/introduction.md b/exercises/concept/wizards-and-warriors/.docs/introduction.md index d2d7333a82..26997c506f 100644 --- a/exercises/concept/wizards-and-warriors/.docs/introduction.md +++ b/exercises/concept/wizards-and-warriors/.docs/introduction.md @@ -1,3 +1,5 @@ +## inheritance + In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class. Parent classes can provide functionality to derived classes in three ways: From da363433191363eda93b703c7b09192a31d4b26b Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Thu, 5 Nov 2020 10:41:11 +0100 Subject: [PATCH 260/327] dictionary ex. tests with only one assert. merged --- .../.docs/introduction.md | 19 +- .../.meta/config.json | 4 + .../InternationalCallingConnoisseur.cs | 4 +- .../InternationalCallingConnoisseurTests.cs | 242 +++++++++++++++--- 4 files changed, 223 insertions(+), 46 deletions(-) diff --git a/exercises/concept/international-calling-connoisseur/.docs/introduction.md b/exercises/concept/international-calling-connoisseur/.docs/introduction.md index 82b2de31a5..8967cbfea8 100644 --- a/exercises/concept/international-calling-connoisseur/.docs/introduction.md +++ b/exercises/concept/international-calling-connoisseur/.docs/introduction.md @@ -5,6 +5,21 @@ A dictionary is a collection of elements where each element comprises a key and A dictionary can be created as follows: ```csharp +new Dictionary(); +// Empty dictionary +``` + +Or + +```csharp +new Dictionary +{ + [1] = "One", + [2] = "Two" +}; + +// Or + new Dictionary { {1, "One"}, @@ -15,7 +30,7 @@ new Dictionary Note that the key and value types are part of the definition of the dictionary. -Once constructed, entries can be added or removed from a dictionary using its built-in methods. +Once constructed, entries can be added or removed from a dictionary using its built-in methods `Add` and `Remove`. Retrieving or updating values in a dictionary is done by indexing into the dictionary using a key: @@ -31,7 +46,7 @@ numbers[2] = "Deux"; // Get the value of the element with key 2 numbers[2]; -// "Deux" +// => "Deux" ``` You can test if a value exists in the dictionary with: diff --git a/exercises/concept/international-calling-connoisseur/.meta/config.json b/exercises/concept/international-calling-connoisseur/.meta/config.json index 66c9974787..94df2358ec 100644 --- a/exercises/concept/international-calling-connoisseur/.meta/config.json +++ b/exercises/concept/international-calling-connoisseur/.meta/config.json @@ -3,6 +3,10 @@ { "github_username": "ErikSchierboom", "exercism_username": "ErikSchierboom" + }, + { + "github_username": "valentin-p", + "exercism_username": "valentin-p" } ], "authors": [ diff --git a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs index 53ea034a67..9c8e17ac1d 100644 --- a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs +++ b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -public class DialingCodes +public static class DialingCodes { public static Dictionary GetEmptyDictionary() { @@ -19,7 +19,7 @@ public static Dictionary AddCountryToEmptyDictionary(int CountryCod } public static Dictionary AddCountryToExistingDictionary( - Dictionary existingDictiopnary, int countryCode, string CountryName) + Dictionary existingDictionary, int countryCode, string CountryName) { throw new NotImplementedException($"Please implement the (static) AddCountryToExistingDictionary() method"); } diff --git a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs index e4ad77f62b..f58c85d1c6 100644 --- a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs +++ b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseurTests.cs @@ -3,39 +3,92 @@ public class DialingCodesTest { [Fact] - public void Empty_dictionary() + public void Empty_dictionary_is_empty() { - Assert.Empty(DialingCodes.GetEmptyDictionary()); + var emptyDict = DialingCodes.GetEmptyDictionary(); + Assert.Empty(emptyDict); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Existing_dictionary() + public void Existing_dictionary_count_is_3() { - var idcd = DialingCodes.GetExistingDictionary(); - Assert.Equal(3, idcd.Count); - Assert.Equal("United States of America", idcd[1]); - Assert.Equal("Brazil", idcd[55]); - Assert.Equal("India", idcd[91]); + var prePopulated = DialingCodes.GetExistingDictionary(); + Assert.Equal(3, prePopulated.Count); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Add_country_to_empty_dictionary() + public void Existing_dictionary_1_is_United_States_of_America() { - var idcd = DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); - Assert.Equal(1, idcd.Count); - Assert.Equal("United Kingdom", idcd[44]); + var prePopulated = DialingCodes.GetExistingDictionary(); + Assert.Equal("United States of America", prePopulated[1]); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Add_country_to_existing_dictionary() + public void Existing_dictionary_55_is_Brazil() { - var idcd = DialingCodes.AddCountryToExistingDictionary( + var prePopulated = DialingCodes.GetExistingDictionary(); + Assert.Equal("Brazil", prePopulated[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Existing_dictionary_91_is_India() + { + var prePopulated = DialingCodes.GetExistingDictionary(); + Assert.Equal("India", prePopulated[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_empty_dictionary_single() + { + var countryCodes = DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); + Assert.Single(countryCodes); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_empty_dictionary_44_is_United_Kingdom() + { + var countryCodes = DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom"); + Assert.Equal("United Kingdom", countryCodes[44]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary_count_is_1() + { + var countryCodes = DialingCodes.AddCountryToExistingDictionary( + DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); + Assert.Equal(4, countryCodes.Count); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary_1_is_United_States_of_America() + { + var countryCodes = DialingCodes.AddCountryToExistingDictionary( + DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); + Assert.Equal("United States of America", countryCodes[1]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary_44_is_United_Kingdom() + { + var countryCodes = DialingCodes.AddCountryToExistingDictionary( + DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); + Assert.Equal("United Kingdom", countryCodes[44]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary_55_is_Brazil() + { + var countryCodes = DialingCodes.AddCountryToExistingDictionary( + DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); + Assert.Equal("Brazil", countryCodes[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Add_country_to_existing_dictionary_91_is_India() + { + var countryCodes = DialingCodes.AddCountryToExistingDictionary( DialingCodes.GetExistingDictionary(), 44, "United Kingdom"); - Assert.Equal(4, idcd.Count); - Assert.Equal("United States of America", idcd[1]); - Assert.Equal("United Kingdom", idcd[44]); - Assert.Equal("Brazil", idcd[55]); - Assert.Equal("India", idcd[91]); + Assert.Equal("India", countryCodes[91]); } [Fact(Skip = "Remove this Skip property to run this test")] @@ -46,6 +99,14 @@ public void Get_country_name_from_dictionary() Assert.Equal("Brazil", countryName); } + [Fact(Skip = "Remove this Skip property to run this test")] + public void Get_country_name_for_non_existent_country() + { + var countryName = DialingCodes.GetCountryNameFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal(string.Empty, countryName); + } + [Fact(Skip = "Remove this Skip property to run this test")] public void Check_country_exists() { @@ -53,51 +114,148 @@ public void Check_country_exists() DialingCodes.GetExistingDictionary(), 55); Assert.True(exists); } + [Fact(Skip = "Remove this Skip property to run this test")] - public void Try_to_get_non_existent_country_name_from_dictionary() + public void Check_country_exists_for_non_existent_country() { - var countryName = DialingCodes.GetCountryNameFromDictionary( + var exists = DialingCodes.CheckCodeExists( DialingCodes.GetExistingDictionary(), 999); - Assert.Equal(string.Empty, countryName); + Assert.False(exists); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_count_is_3() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "les États-Unis"); + Assert.Equal(3, countryCodes.Count); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_1_is_les_Etats_Unis() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "les États-Unis"); + Assert.Equal("les États-Unis", countryCodes[1]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_55_is_Brazil() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "les États-Unis"); + Assert.Equal("Brazil", countryCodes[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_91_is_India() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 1, "les États-Unis"); + Assert.Equal("India", countryCodes[91]); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Update_country_name_in_dictionary() + public void Update_country_name_in_dictionary_for_non_existent_country_count_is_3() { - var idcd = DialingCodes.UpdateDictionary( - DialingCodes.GetExistingDictionary(), 1, "Les États-Unis"); - Assert.Equal(3, idcd.Count); - Assert.Equal("Les États-Unis", idcd[1]); - Assert.Equal("Brazil", idcd[55]); - Assert.Equal("India", idcd[91]); + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 999, "Newlands"); + Assert.Equal(3, countryCodes.Count); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Try_to_update_country_name_in_dictionary_for_non_existent_country() + public void Update_country_name_in_dictionary_for_non_existent_country_1_is_United_States_of_America() { - var idcd = DialingCodes.UpdateDictionary( + var countryCodes = DialingCodes.UpdateDictionary( DialingCodes.GetExistingDictionary(), 999, "Newlands"); - Assert.Equal(3, idcd.Count); - Assert.Equal("United States of America", idcd[1]); - Assert.Equal("Brazil", idcd[55]); - Assert.Equal("India", idcd[91]); + Assert.Equal("United States of America", countryCodes[1]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_for_non_existent_country_55_is_Brazil() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 999, "Newlands"); + Assert.Equal("Brazil", countryCodes[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Update_country_name_in_dictionary_for_non_existent_country_91_is_India() + { + var countryCodes = DialingCodes.UpdateDictionary( + DialingCodes.GetExistingDictionary(), 999, "Newlands"); + Assert.Equal("India", countryCodes[91]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_count_is_2() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 91); + Assert.Equal(2, countryCodes.Count); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_1_is_United_States_of_America() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 91); + Assert.Equal("United States of America", countryCodes[1]); } [Fact(Skip = "Remove this Skip property to run this test")] - public void Remove_country_from_dictionary() + public void Remove_country_from_dictionary_55_is_Brazil() { - var idcd = DialingCodes.RemoveCountryFromDictionary( + var countryCodes = DialingCodes.RemoveCountryFromDictionary( DialingCodes.GetExistingDictionary(), 91); - Assert.Equal(2, idcd.Count); - Assert.Equal("United States of America", idcd[1]); - Assert.Equal("Brazil", idcd[55]); + Assert.Equal("Brazil", countryCodes[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_for_non_existent_country_count_is_3() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal(3, countryCodes.Count); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_for_non_existent_country_1_is_United_States_of_America() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal("United States of America", countryCodes[1]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_for_non_existent_country_55_is_Brazil() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal("Brazil", countryCodes[55]); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Remove_country_from_dictionary_for_non_existent_country_91_is_India() + { + var countryCodes = DialingCodes.RemoveCountryFromDictionary( + DialingCodes.GetExistingDictionary(), 999); + Assert.Equal("India", countryCodes[91]); } [Fact(Skip = "Remove this Skip property to run this test")] public void Longest_country_name() { - var idcd = DialingCodes.FindLongestCountryName( + var longestCountryName = DialingCodes.FindLongestCountryName( DialingCodes.GetExistingDictionary()); - Assert.Equal("United States of America", idcd); + Assert.Equal("United States of America", longestCountryName); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Longest_country_name_for_empty_dictionary() + { + var longestCountryName = DialingCodes.FindLongestCountryName( + DialingCodes.GetEmptyDictionary()); + Assert.Equal(string.Empty, longestCountryName); } } From 044b42648931e45231a3c98e8b3f8d114fa6a79c Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Thu, 5 Nov 2020 15:29:21 +0100 Subject: [PATCH 261/327] instructions.md for empty string --- .../concept/squeaky-clean/.docs/instructions.md | 4 +++- .../concept/squeaky-clean/SqueakyCleanTests.cs | 14 ++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/exercises/concept/squeaky-clean/.docs/instructions.md b/exercises/concept/squeaky-clean/.docs/instructions.md index 83085ef9c3..1e2ac42934 100644 --- a/exercises/concept/squeaky-clean/.docs/instructions.md +++ b/exercises/concept/squeaky-clean/.docs/instructions.md @@ -4,7 +4,9 @@ clean up identifier names. In the 4 tasks you will gradually build up the routine `Clean` A valid identifier comprises zero or more letters and underscores. -In all cases the input string is guaranteed to be non-null. Note that the `Clean` method should treat an empty string as valid. +In all cases the input string is guaranteed to be non-null. If an empty string is passed to the `Clean` function, an empty string should be returned. + +Note that the caller should avoid calling the routine `Clean` with an empty identifier since such identifiers are ineffectual. ### 1. Replace any spaces encountered with underscores diff --git a/exercises/concept/squeaky-clean/SqueakyCleanTests.cs b/exercises/concept/squeaky-clean/SqueakyCleanTests.cs index d30f44f9a5..44ec85be12 100644 --- a/exercises/concept/squeaky-clean/SqueakyCleanTests.cs +++ b/exercises/concept/squeaky-clean/SqueakyCleanTests.cs @@ -3,12 +3,6 @@ public class CharsTest { [Fact] - public void Clean_empty_string() - { - Assert.Equal(string.Empty, Identifier.Clean(string.Empty)); - } - - [Fact(Skip = "Remove this Skip property to run this test")] public void Clean_single_letter() { Assert.Equal("A", Identifier.Clean("A")); @@ -38,6 +32,12 @@ public void Clean_string_with_no_letters() Assert.Equal(string.Empty, Identifier.Clean("😀😀😀")); } + [Fact(Skip = "Remove this Skip property to run this test")] + public void Clean_empty_string() + { + Assert.Equal(string.Empty, Identifier.Clean(string.Empty)); + } + [Fact(Skip = "Remove this Skip property to run this test")] public void Convert_kebab_to_camel_case() { @@ -55,6 +55,4 @@ public void Combine_conversions() { Assert.Equal("_AbcĐCTRL", Identifier.Clean("9 -abcĐ😀ω\0")); } - - } From 5bf0e1dfbd7fea2858afd757f205b06949d018ec Mon Sep 17 00:00:00 2001 From: Mike May Date: Fri, 6 Nov 2020 09:16:59 -0500 Subject: [PATCH 262/327] rename high school sweethearts classes manual construction of about.md to avoid merge conflicts * high-school-sweethearts - changed class name --- .../high-school-sweethearts/.docs/instructions.md | 12 ++++++------ .../concept/high-school-sweethearts/.meta/Example.cs | 2 +- .../high-school-sweethearts/HighSchoolSweethearts.cs | 8 ++++---- .../HighSchoolSweetheartsTests.cs | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/exercises/concept/high-school-sweethearts/.docs/instructions.md b/exercises/concept/high-school-sweethearts/.docs/instructions.md index 9e2612ff3c..0b2fa4867f 100644 --- a/exercises/concept/high-school-sweethearts/.docs/instructions.md +++ b/exercises/concept/high-school-sweethearts/.docs/instructions.md @@ -2,21 +2,21 @@ In this exercise, you are going to help high school sweethearts profess their lo ## 1. Display the couple's name separated by a heart -Please implement the static `HighSchoolSweetheart.DisplaySingleLine()` method to take 2 names and display them separated by a heart centered in a 61 character line. +Please implement the static `HighSchoolSweethearts.DisplaySingleLine()` method to take 2 names and display them separated by a heart centered in a 61 character line. All names are guaranteed to fit well within the width of the line. ```csharp -HighSchoolSweetheart.DisplaySingleLine("Lance Green", "Pat Riley"); +HighSchoolSweethearts.DisplaySingleLine("Lance Green", "Pat Riley"); // => " Lance Green ♡ Pat Riley " ``` ## 2. Display the couple's initials in an ascii art heart -Implement the static `HighSchoolSweetheart.DisplayBanner()` method which displays the two sets of initials separated with a plus sign. +Implement the static `HighSchoolSweethearts.DisplayBanner()` method which displays the two sets of initials separated with a plus sign. ```csharp -HighSchoolSweetheart.DisplayBanner("L. G.", "P. R."); +HighSchoolSweethearts.DisplayBanner("L. G.", "P. R."); // see the ascii art below ``` @@ -39,9 +39,9 @@ HighSchoolSweetheart.DisplayBanner("L. G.", "P. R."); ## 3. German exchange students should be made to feel at home with locale-sensitive declarations. -Implement the static `HighSchoolSweetheart.DisplayGermanExchangeStudents()` method to show date of start of relationship and length of time for our german exchange students. +Implement the static `HighSchoolSweethearts.DisplayGermanExchangeStudents()` method to show date of start of relationship and length of time for our german exchange students. ```csharp -HighSchoolSweetheart.DisplayGermanExchangeStudents("Norbert", "Heidi", new DateTime(2019, 1, 22), 1535.22f); +HighSchoolSweethearts.DisplayGermanExchangeStudents("Norbert", "Heidi", new DateTime(2019, 1, 22), 1535.22f); // => "Norbert and Heidi have been dating since 22.01.2019 - that's 1.535,22 hours" ``` diff --git a/exercises/concept/high-school-sweethearts/.meta/Example.cs b/exercises/concept/high-school-sweethearts/.meta/Example.cs index 2dd15993ef..ee39754925 100644 --- a/exercises/concept/high-school-sweethearts/.meta/Example.cs +++ b/exercises/concept/high-school-sweethearts/.meta/Example.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; -public static class HighSchoolSweetheart +public static class HighSchoolSweethearts { private const string banner = @" diff --git a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs index 8fee3825b4..4352ff86d6 100644 --- a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs +++ b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.cs @@ -1,20 +1,20 @@ using System; -public static class HighSchoolSweetheart +public static class HighSchoolSweethearts { public static string DisplaySingleLine(string studentA, string studentB) { - throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplaySingleLine() method"); + throw new NotImplementedException($"Please implement the (static) HighSchoolSweethearts.DisplaySingleLine() method"); } public static string DisplayBanner(string studentA, string studentB) { - throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplayBanner() method"); + throw new NotImplementedException($"Please implement the (static) HighSchoolSweethearts.DisplayBanner() method"); } public static string DisplayGermanExchangeStudents(string studentA , string studentB, DateTime start, float hours) { - throw new NotImplementedException($"Please implement the (static) HighSchoolSweetheart.DisplayGermanExchangeStudents() method"); + throw new NotImplementedException($"Please implement the (static) HighSchoolSweethearts.DisplayGermanExchangeStudents() method"); } } diff --git a/exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs b/exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs index 6a62d36ebc..9553c2c933 100644 --- a/exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs +++ b/exercises/concept/high-school-sweethearts/HighSchoolSweetheartsTests.cs @@ -24,20 +24,20 @@ public class StringFormattingTests public void DisplaySingleLine() { const string expected = " Lance Green ♡ Pat Riley "; - Assert.Equal(expected, HighSchoolSweetheart.DisplaySingleLine("Lance Green", "Pat Riley")); + Assert.Equal(expected, HighSchoolSweethearts.DisplaySingleLine("Lance Green", "Pat Riley")); } [Fact(Skip = "Remove this Skip property to run this test")] public void DisplayBanner() { - string actualBanner = HighSchoolSweetheart.DisplayBanner("L. G. ", "P. R. "); + string actualBanner = HighSchoolSweethearts.DisplayBanner("L. G. ", "P. R. "); Assert.Equal(expectedBanner.Trim(), actualBanner.Trim()); } [Fact(Skip = "Remove this Skip property to run this test")] public void DisplayGermanExchangeStudents() { - string actual = HighSchoolSweetheart.DisplayGermanExchangeStudents("Norbert", "Heidi", + string actual = HighSchoolSweethearts.DisplayGermanExchangeStudents("Norbert", "Heidi", new DateTime(2019, 1, 22), 1535.22f); Assert.Equal("Norbert and Heidi have been dating since 22.01.2019 - that's 1.535,22 hours" , actual); From b9c0b0c35dfcb3b1ed8e1298013d2782d1cb3ea6 Mon Sep 17 00:00:00 2001 From: Mike May Date: Sat, 7 Nov 2020 13:02:31 +0000 Subject: [PATCH 263/327] minor concept changes manual construction of about.md to avoid merge conflicts * minor-concept-changes renamed conditionals-ternary directory to ternary-operators * minor-concept-changes substituted conditionals-ternary text with ternary-operators * minor-concept-changes deleted concepts/accessibility directory * minor-concept-changes delete mentions of accessibility concept * minor-concept-changes delete pattern-matching-constants directory * minor-concept-changes delete mentions of pattern-matching-constants concept --- concepts/accessibility/about.md | 1 - concepts/accessibility/links.json | 1 - concepts/pattern-matching-constants/about.md | 1 - concepts/pattern-matching-constants/links.json | 1 - .../about.md | 0 .../links.json | 0 exercises/concept/logs-logs-logs/.meta/design.md | 1 - .../concept/red-vs-blue-darwin-style/.meta/design.md | 1 - .../concept/the-weather-in-deather/.meta/design.md | 2 +- reference/exercises.json | 12 +----------- 10 files changed, 2 insertions(+), 18 deletions(-) delete mode 100644 concepts/accessibility/about.md delete mode 100644 concepts/accessibility/links.json delete mode 100644 concepts/pattern-matching-constants/about.md delete mode 100644 concepts/pattern-matching-constants/links.json rename concepts/{conditionals-ternary => ternary-operators}/about.md (100%) rename concepts/{conditionals-ternary => ternary-operators}/links.json (100%) diff --git a/concepts/accessibility/about.md b/concepts/accessibility/about.md deleted file mode 100644 index cad71de6bb..0000000000 --- a/concepts/accessibility/about.md +++ /dev/null @@ -1 +0,0 @@ -TODO: add information on accessibility concept diff --git a/concepts/accessibility/links.json b/concepts/accessibility/links.json deleted file mode 100644 index fe51488c70..0000000000 --- a/concepts/accessibility/links.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/concepts/pattern-matching-constants/about.md b/concepts/pattern-matching-constants/about.md deleted file mode 100644 index b5ce60fc22..0000000000 --- a/concepts/pattern-matching-constants/about.md +++ /dev/null @@ -1 +0,0 @@ -TODO: add information on pattern-matching-constants concept diff --git a/concepts/pattern-matching-constants/links.json b/concepts/pattern-matching-constants/links.json deleted file mode 100644 index fe51488c70..0000000000 --- a/concepts/pattern-matching-constants/links.json +++ /dev/null @@ -1 +0,0 @@ -[] diff --git a/concepts/conditionals-ternary/about.md b/concepts/ternary-operators/about.md similarity index 100% rename from concepts/conditionals-ternary/about.md rename to concepts/ternary-operators/about.md diff --git a/concepts/conditionals-ternary/links.json b/concepts/ternary-operators/links.json similarity index 100% rename from concepts/conditionals-ternary/links.json rename to concepts/ternary-operators/links.json diff --git a/exercises/concept/logs-logs-logs/.meta/design.md b/exercises/concept/logs-logs-logs/.meta/design.md index c414cc43a3..b14f9e187f 100644 --- a/exercises/concept/logs-logs-logs/.meta/design.md +++ b/exercises/concept/logs-logs-logs/.meta/design.md @@ -18,7 +18,6 @@ After completing this exercise, the student should: ## Concepts - `enums`: know of the existence of the `enum` keyword; know how to define enum members; know how to assign values to enum members; know how to get an enum's numeric value; know how to convert an `enum` to a `string`. -- `pattern-matching-constants`: know how to use the `switch` statement to do constant pattern matching. ## Prerequisites diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/design.md b/exercises/concept/red-vs-blue-darwin-style/.meta/design.md index 3cb7cf8bf2..88c24ce4df 100644 --- a/exercises/concept/red-vs-blue-darwin-style/.meta/design.md +++ b/exercises/concept/red-vs-blue-darwin-style/.meta/design.md @@ -10,7 +10,6 @@ ## Concepts - `namespaces`: know what namespaces are; know how to import namespaces. -- `accessibility`: know how to use access modifiers to limit access to elements. - `imports`: know how to import namespaces with the `using` directive ## Prerequisites diff --git a/exercises/concept/the-weather-in-deather/.meta/design.md b/exercises/concept/the-weather-in-deather/.meta/design.md index d3e067ea36..e5d5f559d1 100644 --- a/exercises/concept/the-weather-in-deather/.meta/design.md +++ b/exercises/concept/the-weather-in-deather/.meta/design.md @@ -15,7 +15,7 @@ ## Concepts - `expression-bodied-members`: know the difference between statements and expressions; know how to define expression bodied members. -- `conditionals-ternary`: know how and when to use the ternary operator. +- `ternary-operators`: know how and when to use the ternary operator. - `throw-expressions`: know how to use a `throw` expression. - `switch-expressions`: know how to pattern match on values; know how to use `when` guards diff --git a/reference/exercises.json b/reference/exercises.json index 2f1ed7b353..7274290011 100644 --- a/reference/exercises.json +++ b/reference/exercises.json @@ -549,11 +549,6 @@ "line-number": 155 } ] - }, - { - "name": "pattern-matching-constants", - "track-neutral-concept": "", - "original-concepts": [] } ] }, @@ -1048,7 +1043,7 @@ ] }, { - "name": "conditionals-ternary", + "name": "ternary-operators", "track-neutral-concept": "reference/concepts/conditionals.md", "original-concepts": [ { @@ -1085,11 +1080,6 @@ } ] }, - { - "name": "accessibility", - "track-neutral-concept": "", - "original-concepts": [] - }, { "name": "imports", "track-neutral-concept": "", From b56cb10f7961e05f1906647824f6f67726a2c313 Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Tue, 10 Nov 2020 08:23:31 +0100 Subject: [PATCH 264/327] format multiple files --- .../authentication-system/.meta/Example.cs | 2 +- .../AuthenticationSystemTests.cs | 8 +- .../BeautySalonGoesGlobalTests.cs | 10 +-- .../football-match-reports/.meta/Example.cs | 2 +- .../.meta/Example.cs | 8 +- .../HyperOptimizedTelemetryTests.cs | 86 +++++++++---------- .../concept/hyperia-forex/.meta/Example.cs | 6 +- .../HyperinflationHitsHyperiaTests.cs | 2 +- .../land-grab-in-space/.meta/Example.cs | 2 +- .../ObjectRelationalMappingTests.cs | 26 +++--- .../concept/orm-in-one-go/OrmInOneGoTests.cs | 2 +- .../parsing-log-files/ParsingLogFilesTests.cs | 4 +- .../.meta/Example.cs | 2 +- .../RemoteControlCompetitionTests.cs | 4 +- .../secure-munchester-united/.meta/Example.cs | 4 +- .../SecureMunchesterUnited.cs | 4 +- .../TheWeatherInDeatherTests.cs | 8 +- .../why-cant-i-push-to-main/.meta/Example.cs | 6 +- 18 files changed, 93 insertions(+), 93 deletions(-) diff --git a/exercises/concept/authentication-system/.meta/Example.cs b/exercises/concept/authentication-system/.meta/Example.cs index ba5fb61178..77b62b8aad 100644 --- a/exercises/concept/authentication-system/.meta/Example.cs +++ b/exercises/concept/authentication-system/.meta/Example.cs @@ -37,7 +37,7 @@ private readonly IDictionary developers public Identity Admin { - get { return new Identity {Email = admin.Email, EyeColor = admin.EyeColor}; } + get { return new Identity { Email = admin.Email, EyeColor = admin.EyeColor }; } } public IReadOnlyDictionary GetDevelopers() diff --git a/exercises/concept/authentication-system/AuthenticationSystemTests.cs b/exercises/concept/authentication-system/AuthenticationSystemTests.cs index 9c9346888d..46f1b095e2 100644 --- a/exercises/concept/authentication-system/AuthenticationSystemTests.cs +++ b/exercises/concept/authentication-system/AuthenticationSystemTests.cs @@ -7,7 +7,7 @@ public class ObjectInitializationTests [Fact] public void GetAdmin() { - var admin = new Identity {EyeColor = "green", Email = "admin@ex.ism"}; + var admin = new Identity { EyeColor = "green", Email = "admin@ex.ism" }; var authenticator = new Authenticator(admin); Assert.Equal(admin, authenticator.Admin); } @@ -15,10 +15,10 @@ public void GetAdmin() [Fact] public void GetDevelopers() { - var authenticator = new Authenticator(new Identity {EyeColor = "green", Email = "admin@ex.ism"}); + var authenticator = new Authenticator(new Identity { EyeColor = "green", Email = "admin@ex.ism" }); var devs = authenticator.GetDevelopers() as IDictionary; - bool?[] actual = {devs != null, devs?.Count == 2, devs?["Anders"].EyeColor == "brown"}; - bool?[] expected = {true, true, true}; + bool?[] actual = { devs != null, devs?.Count == 2, devs?["Anders"].EyeColor == "brown" }; + bool?[] expected = { true, true, true }; Assert.Equal(expected, actual); } } diff --git a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs index 6ac57e3d67..994dd01599 100644 --- a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs +++ b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobalTests.cs @@ -20,7 +20,7 @@ public void ShowLocalTime() var offset = tzi.GetUtcOffset(dt); Assert.Equal(dt + offset, Appointment.ShowLocalTime(dt)); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void Schedule_newyork() { @@ -141,7 +141,7 @@ public void DalylightSavingChanged_paris_no_change() [Fact(Skip = "Remove this Skip property to run this test")] public void NormalizeDateTime_newyork() { - Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Assert.Equal(new DateTime(2019, 11, 25, 13, 45, 0), Appointment.NormalizeDateTime("11/25/2019 13:45:00", Location.NewYork)); } @@ -149,7 +149,7 @@ public void NormalizeDateTime_newyork() [Fact(Skip = "Remove this Skip property to run this test")] public void NormalizeDateTime_london() { - Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Assert.Equal(new DateTime(2019, 11, 25, 13, 45, 0), Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.London)); } @@ -157,7 +157,7 @@ public void NormalizeDateTime_london() [Fact(Skip = "Remove this Skip property to run this test")] public void NormalizeDateTime_paris() { - Assert.Equal( new DateTime(2019, 11, 25, 13, 45, 0), + Assert.Equal(new DateTime(2019, 11, 25, 13, 45, 0), Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.Paris)); } @@ -165,7 +165,7 @@ public void NormalizeDateTime_paris() [Fact(Skip = "Remove this Skip property to run this test")] public void NormalizeDateTime_bad() { - Assert.Equal( DateTime.MinValue, + Assert.Equal(DateTime.MinValue, Appointment.NormalizeDateTime("25/11/2019 13:45:00", Location.NewYork)); } diff --git a/exercises/concept/football-match-reports/.meta/Example.cs b/exercises/concept/football-match-reports/.meta/Example.cs index 4eff6e9812..c71b89cafb 100644 --- a/exercises/concept/football-match-reports/.meta/Example.cs +++ b/exercises/concept/football-match-reports/.meta/Example.cs @@ -101,4 +101,4 @@ public class Foul : Incident public class Injury : Incident { public override string GetDescription() => "A player is injured."; -} \ No newline at end of file +} diff --git a/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs b/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs index 29dd78745a..8ea5d3314c 100644 --- a/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs +++ b/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs @@ -22,25 +22,25 @@ public static byte[] ToBuffer(long reading) else if (reading > UInt16.MaxValue || reading < Int16.MinValue) { allBytes[0] = 0xfc; - bytes = BitConverter.GetBytes((int) reading); + bytes = BitConverter.GetBytes((int)reading); bytes.CopyTo(allBytes, 1); } else if (reading > Int16.MaxValue) { allBytes[0] = 0x2; - bytes = BitConverter.GetBytes((ushort) reading); + bytes = BitConverter.GetBytes((ushort)reading); bytes.CopyTo(allBytes, 1); } else if (reading >= 0) { allBytes[0] = 0xfe; - bytes = BitConverter.GetBytes((ushort) reading); + bytes = BitConverter.GetBytes((ushort)reading); bytes.CopyTo(allBytes, 1); } else { allBytes[0] = 0xfe; - bytes = BitConverter.GetBytes((short) reading); + bytes = BitConverter.GetBytes((short)reading); bytes.CopyTo(allBytes, 1); } diff --git a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs index 3fb6748d1d..dbeb2b360f 100644 --- a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs +++ b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetryTests.cs @@ -9,84 +9,84 @@ public class TelemetryBufferTests public void ToBuffer_upper_long() { var bytes = TelemetryBuffer.ToBuffer(Int64.MaxValue); - Assert.Equal(new byte[] {0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, bytes); + Assert.Equal(new byte[] { 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_long() { var bytes = TelemetryBuffer.ToBuffer((long)UInt32.MaxValue + 1); - Assert.Equal(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_uint() { var bytes = TelemetryBuffer.ToBuffer(UInt32.MaxValue); - Assert.Equal(new byte[] {0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_uint() { var bytes = TelemetryBuffer.ToBuffer((long)Int32.MaxValue + 1); - Assert.Equal(new byte[] {0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_int() { var bytes = TelemetryBuffer.ToBuffer(Int32.MaxValue); - Assert.Equal(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_int() { var bytes = TelemetryBuffer.ToBuffer((long)UInt16.MaxValue + 1); - Assert.Equal(new byte[] {0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_ushort() { var bytes = TelemetryBuffer.ToBuffer(UInt16.MaxValue); - Assert.Equal(new byte[] {0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_ushort() { var bytes = TelemetryBuffer.ToBuffer((long)Int16.MaxValue + 1); - Assert.Equal(new byte[] {0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_short() { var bytes = TelemetryBuffer.ToBuffer(Int16.MaxValue); - Assert.Equal(new byte[] {0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_Zero() { var bytes = TelemetryBuffer.ToBuffer(0); - Assert.Equal(new byte[] {0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, bytes); + Assert.Equal(new byte[] { 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_neg_short() { var bytes = TelemetryBuffer.ToBuffer(-1); - Assert.Equal(new byte[] {0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_neg_short() { var bytes = TelemetryBuffer.ToBuffer(Int16.MinValue); - Assert.Equal(new byte[] {0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] @@ -94,147 +94,147 @@ public void ToBuffer_upper_neg_int() { int n = Int16.MinValue - 1; var bytes = TelemetryBuffer.ToBuffer(n); - Assert.Equal(new byte[] {0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_neg_int() { var bytes = TelemetryBuffer.ToBuffer(Int32.MinValue); - Assert.Equal(new byte[] {0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); + Assert.Equal(new byte[] { 0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_upper_neg_long() { var bytes = TelemetryBuffer.ToBuffer((long)Int32.MinValue - 1); - Assert.Equal(new byte[] {0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff }, bytes); + Assert.Equal(new byte[] { 0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff }, bytes); } [Fact(Skip = "Remove this Skip property to run this test")] public void ToBuffer_lower_neg_long() { var bytes = TelemetryBuffer.ToBuffer(Int64.MinValue); - Assert.Equal(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 }, bytes); + Assert.Equal(new byte[] { 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 }, bytes); } - [Fact (Skip = "Remove this Skip property to run this test")] + [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_Invalid() { Assert.Equal(0, - TelemetryBuffer.FromBuffer(new byte[] {22, 0xff, 0xff, 0xff, 0x7f, 0, 0, 0, 0 })); + TelemetryBuffer.FromBuffer(new byte[] { 22, 0xff, 0xff, 0xff, 0x7f, 0, 0, 0, 0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_long() { Assert.Equal(Int64.MaxValue, - TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f })); + TelemetryBuffer.FromBuffer(new byte[] { 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_long() { Assert.Equal((long)UInt32.MaxValue + 1, - TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xf8, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_uint() { Assert.Equal(UInt32.MaxValue, - TelemetryBuffer.FromBuffer(new byte[] {0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0})); + TelemetryBuffer.FromBuffer(new byte[] { 0x4, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_uint() { Assert.Equal((long)Int32.MaxValue + 1, - TelemetryBuffer.FromBuffer(new byte[] {0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0x4, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_int() { Assert.Equal(Int32.MaxValue, - TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfc, 0xff, 0xff, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_int() { Assert.Equal(UInt16.MaxValue + 1, - TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfc, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_ushort() { Assert.Equal(UInt16.MaxValue, - TelemetryBuffer.FromBuffer(new byte[] {0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0x2, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_ushort() { Assert.Equal(Int16.MaxValue + 1, - TelemetryBuffer.FromBuffer(new byte[] {0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0x2, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_short() { Assert.Equal(Int16.MaxValue, - TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfe, 0xff, 0x7f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_Zero() { Assert.Equal(0, - TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0})); + TelemetryBuffer.FromBuffer(new byte[] { 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_neg_short() { Assert.Equal(-1, - TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfe, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_neg_short() { Assert.Equal(Int16.MinValue, - TelemetryBuffer.FromBuffer(new byte[] {0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfe, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_neg_int() { Assert.Equal(Int16.MinValue - 1, - TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfc, 0xff, 0x7f, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_neg_int() { Assert.Equal(Int32.MinValue, - TelemetryBuffer.FromBuffer(new byte[] {0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xfc, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0 })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_upper_neg_long() { Assert.Equal((long)Int32.MinValue - 1, - TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff })); + TelemetryBuffer.FromBuffer(new byte[] { 0xf8, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff })); } [Fact(Skip = "Remove this Skip property to run this test")] public void FromBuffer_lower_neg_long() { Assert.Equal(Int64.MinValue, - TelemetryBuffer.FromBuffer(new byte[] {0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 })); + TelemetryBuffer.FromBuffer(new byte[] { 0xf8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80 })); } } } diff --git a/exercises/concept/hyperia-forex/.meta/Example.cs b/exercises/concept/hyperia-forex/.meta/Example.cs index d231242df6..96692b2581 100644 --- a/exercises/concept/hyperia-forex/.meta/Example.cs +++ b/exercises/concept/hyperia-forex/.meta/Example.cs @@ -87,12 +87,12 @@ public CurrencyAmount(decimal amount, string currency) return new CurrencyAmount(@this.amount / divisor, @this.currency); } - public static explicit operator double (CurrencyAmount @this) + public static explicit operator double(CurrencyAmount @this) { - return (double) @this.amount; + return (double)@this.amount; } - public static implicit operator decimal (CurrencyAmount @this) + public static implicit operator decimal(CurrencyAmount @this) { return @this.amount; } diff --git a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs index 19e8e17633..5529c83a3c 100644 --- a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs +++ b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperiaTests.cs @@ -12,7 +12,7 @@ public void DisplayDenomination_good() [Fact(Skip = "Remove this Skip property to run this test")] public void DisplayDenomination_bad() { - Assert.Equal("*** Too Big ***", CentralBank.DisplayDenomination( long.MaxValue / 2L, 10000L)); + Assert.Equal("*** Too Big ***", CentralBank.DisplayDenomination(long.MaxValue / 2L, 10000L)); } [Fact(Skip = "Remove this Skip property to run this test")] diff --git a/exercises/concept/land-grab-in-space/.meta/Example.cs b/exercises/concept/land-grab-in-space/.meta/Example.cs index 64afd3b8f1..588ccb9ac3 100644 --- a/exercises/concept/land-grab-in-space/.meta/Example.cs +++ b/exercises/concept/land-grab-in-space/.meta/Example.cs @@ -35,7 +35,7 @@ public ushort GetLongestSide() TopRight.X - TopLeft.X, Math.Max(BottomRight.X - BottomLeft.X, Math.Max(BottomRight.Y - TopRight.Y - ,BottomLeft.Y - TopLeft.Y))); + , BottomLeft.Y - TopLeft.Y))); } } diff --git a/exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs b/exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs index 59e20d100a..204dd748a6 100644 --- a/exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs +++ b/exercises/concept/object-relational-mapping/ObjectRelationalMappingTests.cs @@ -12,8 +12,8 @@ public void Write_good() var orm = new Orm(db); orm.Begin(); orm.Write("good write"); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] { Database.State.DataWritten, "good write"}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.DataWritten, "good write" }, actual); } [Fact /*(Skip = "Remove this Skip property to run this test")*/] @@ -23,8 +23,8 @@ public void Write_bad() var orm = new Orm(db); orm.Begin(); orm.Write("bad write"); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] { Database.State.Closed, "bad write"}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.Closed, "bad write" }, actual); } [Fact /*(Skip = "Remove this Skip property to run this test")*/] @@ -35,8 +35,8 @@ public void Commit_good() orm.Begin(); orm.Write("good commit"); orm.Commit(); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] { Database.State.Closed, "good commit"}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.Closed, "good commit" }, actual); } [Fact /*(Skip = "Remove this Skip property to run this test")*/] @@ -47,8 +47,8 @@ public void Commit_bad() orm.Begin(); orm.Write("bad commit"); orm.Commit(); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] { Database.State.Closed, "bad commit"}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.Closed, "bad commit" }, actual); } [Fact /*(Skip = "Remove this Skip property to run this test")*/] @@ -58,8 +58,8 @@ public void Out_of_order() var orm = new Orm(db); orm.Write("bad commit"); orm.Commit(); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] { Database.State.Closed, string.Empty}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.Closed, string.Empty }, actual); } [Fact /*(Skip = "Remove this Skip property to run this test")*/] @@ -71,15 +71,15 @@ public void Disposable() orm.Write("good data"); var disposable = Assert.IsAssignableFrom(orm); disposable.Dispose(); - object[] actual = {db.DbState, db.lastData}; - Assert.Equal(new object[] {Database.State.Closed, "good data"}, actual); + object[] actual = { db.DbState, db.lastData }; + Assert.Equal(new object[] { Database.State.Closed, "good data" }, actual); } } // **** please do not modify the Database class **** public class Database : IDisposable { - public enum State {TransactionStarted, DataWritten, Invalid, Closed} + public enum State { TransactionStarted, DataWritten, Invalid, Closed } public State DbState { get; private set; } = State.Closed; public string lastData = string.Empty; diff --git a/exercises/concept/orm-in-one-go/OrmInOneGoTests.cs b/exercises/concept/orm-in-one-go/OrmInOneGoTests.cs index 15c1023b64..66f88eb132 100644 --- a/exercises/concept/orm-in-one-go/OrmInOneGoTests.cs +++ b/exercises/concept/orm-in-one-go/OrmInOneGoTests.cs @@ -82,7 +82,7 @@ public void CommitSafely_bad_commit() // **** please do not modify the Database class **** public class Database : IDisposable { - public enum State {TransactionStarted, DataWritten, Invalid, Closed} + public enum State { TransactionStarted, DataWritten, Invalid, Closed } public static State DbState { get; private set; } = State.Closed; public static string lastData = string.Empty; diff --git a/exercises/concept/parsing-log-files/ParsingLogFilesTests.cs b/exercises/concept/parsing-log-files/ParsingLogFilesTests.cs index 3e8254f80a..a112722635 100644 --- a/exercises/concept/parsing-log-files/ParsingLogFilesTests.cs +++ b/exercises/concept/parsing-log-files/ParsingLogFilesTests.cs @@ -21,14 +21,14 @@ public void IsMatch_no_match() public void SplitLogLine() { var lp = new LogParser(); - Assert.Equal(new string[] {"section 1", "section 2", "section 3"}, lp.SplitLogLine("section 1<^>section 2<--->section 3")); + Assert.Equal(new string[] { "section 1", "section 2", "section 3" }, lp.SplitLogLine("section 1<^>section 2<--->section 3")); } [Fact(Skip = "Remove this Skip property to run this test")] public void SplitLogLine_Empty() { var lp = new LogParser(); - Assert.Equal(new string[] {string.Empty}, lp.SplitLogLine(string.Empty)); + Assert.Equal(new string[] { string.Empty }, lp.SplitLogLine(string.Empty)); } diff --git a/exercises/concept/remote-control-competition/.meta/Example.cs b/exercises/concept/remote-control-competition/.meta/Example.cs index 6266723e50..23fb960cb7 100644 --- a/exercises/concept/remote-control-competition/.meta/Example.cs +++ b/exercises/concept/remote-control-competition/.meta/Example.cs @@ -46,7 +46,7 @@ public static decimal Race(IRemoteControlCar car) public static List GetRankedCars(ProductionRemoteControlCar prc1, ProductionRemoteControlCar prc2) { - var rankings = new List{prc1, prc2}; + var rankings = new List { prc1, prc2 }; rankings.Sort(); return rankings; } diff --git a/exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs b/exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs index 4a136447f7..0c8e44753e 100644 --- a/exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs +++ b/exercises/concept/remote-control-competition/RemoteControlCompetitionTests.cs @@ -35,8 +35,8 @@ public void EnsureCarsAreComparable() fast.NumberOfVictories = 3; medium.NumberOfVictories = 2; slow.NumberOfVictories = 1; - var cars = new List {fast, slow, medium}; + var cars = new List { fast, slow, medium }; cars.Sort(); - Assert.Equal(new ProductionRemoteControlCar[] {slow, medium, fast}, cars); + Assert.Equal(new ProductionRemoteControlCar[] { slow, medium, fast }, cars); } } diff --git a/exercises/concept/secure-munchester-united/.meta/Example.cs b/exercises/concept/secure-munchester-united/.meta/Example.cs index 1056e334d1..44ed992040 100644 --- a/exercises/concept/secure-munchester-united/.meta/Example.cs +++ b/exercises/concept/secure-munchester-united/.meta/Example.cs @@ -21,9 +21,9 @@ public string GetDisplayName(TeamSupport support) /**** Please do not alter the code below ****/ -public interface TeamSupport {string Title { get; } } +public interface TeamSupport { string Title { get; } } -public abstract class Staff : TeamSupport { public abstract string Title { get; }} +public abstract class Staff : TeamSupport { public abstract string Title { get; } } public class Manager : TeamSupport { public string Title { get; } = "The Manager"; } diff --git a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs index 6810d504cc..d0181296ee 100644 --- a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs +++ b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.cs @@ -10,9 +10,9 @@ public string GetDisplayName(TeamSupport support) /**** Please do not alter the code below ****/ -public interface TeamSupport {string Title { get; } } +public interface TeamSupport { string Title { get; } } -public abstract class Staff : TeamSupport { public abstract string Title { get; }} +public abstract class Staff : TeamSupport { public abstract string Title { get; } } public class Manager : TeamSupport { public string Title { get; } = "The Manager"; } diff --git a/exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs b/exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs index cf34c437a8..cc5ecea30e 100644 --- a/exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs +++ b/exercises/concept/the-weather-in-deather/TheWeatherInDeatherTests.cs @@ -8,8 +8,8 @@ public void GetReading() { var ws = new WeatherStation(); ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); - decimal[] expected = {20, 25, 0.01m}; - decimal[] actual = {ws.LatestTemperature, ws.LatestPressure, ws.LatestRainfall}; + decimal[] expected = { 20, 25, 0.01m }; + decimal[] actual = { ws.LatestTemperature, ws.LatestPressure, ws.LatestRainfall }; Assert.Equal(expected, actual); } @@ -37,8 +37,8 @@ public void ClearAll() ws.AcceptReading(new Reading(20m, 25m, 0.01m, WindDirection.Unknown)); ws.AcceptReading(new Reading(21m, 25m, 0.00m, WindDirection.Unknown)); ws.ClearAll(); - object[] expected = {false, 0m}; - object[] actual = {ws.HasHistory, ws.LatestTemperature}; + object[] expected = { false, 0m }; + object[] actual = { ws.HasHistory, ws.LatestTemperature }; Assert.Equal(expected, actual); } diff --git a/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs b/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs index 27713e49b4..32f53011cd 100644 --- a/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs +++ b/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs @@ -11,7 +11,7 @@ public class Authenticator EyeColor = "green", PhiltrumWidth = 0.9m }, - NameAndAddress = new List{"Chanakya", "Mombai", "India"} + NameAndAddress = new List { "Chanakya", "Mombai", "India" } }; public IDictionary Developers { get; } @@ -25,7 +25,7 @@ public class Authenticator EyeColor = "blue", PhiltrumWidth = 0.8m }, - NameAndAddress = new List{"Bertrand", "Paris", "France"} + NameAndAddress = new List { "Bertrand", "Paris", "France" } }, ["Anders"] = new Identity @@ -36,7 +36,7 @@ public class Authenticator EyeColor = "brown", PhiltrumWidth = 0.85m }, - NameAndAddress = new List{"Anders", "Redmond", "USA"} + NameAndAddress = new List { "Anders", "Redmond", "USA" } } }; } From c2a4f71498fb912e0322e7487c2ac8b7711d87c7 Mon Sep 17 00:00:00 2001 From: valentin-p <3833193+valentin-p@users.noreply.github.com> Date: Wed, 11 Nov 2020 08:20:17 +0100 Subject: [PATCH 265/327] calculator cyclic dep improv 2314 * draft new example and remove cyclic dep --- .../.docs/instructions.md | 12 +----- .../.docs/introduction.md | 16 ++++---- .../calculator-conundrum/.meta/Example.cs | 40 ++++++++----------- .../calculator-conundrum/.meta/config.json | 6 +++ .../calculator-conundrum/.meta/design.md | 4 +- .../CalculatorConundrum.cs | 21 +++++----- .../CalculatorConundrumTests.cs | 21 +++------- 7 files changed, 48 insertions(+), 72 deletions(-) diff --git a/exercises/concept/calculator-conundrum/.docs/instructions.md b/exercises/concept/calculator-conundrum/.docs/instructions.md index c01346028b..e6712b24fa 100644 --- a/exercises/concept/calculator-conundrum/.docs/instructions.md +++ b/exercises/concept/calculator-conundrum/.docs/instructions.md @@ -22,17 +22,7 @@ The main method for implementation in this task will be the (_static_) `SimpleCa Any other operation symbol should throw the `ArgumentOutOfRangeException` exception. If the operation argument is an empty string, then the method should throw the `ArgumentException` exception. When `null` is provided as an operation argument, then the method should throw the `ArgumentNullException` exception. This functionality and handling of operations should be contained in a `try` block. -## 3. Handle the thrown Overflow exceptions - -When the `OverflowException` exception gets thrown, the code handling the exception should return the string of the following content: `The result of operation {operand1} {operation} {operand2} does not fit into integer type.`. - -```csharp -SimpleCalculator.Calculate(2_147_483_647, 2, "+"); // => returns "The result of operation 2147483647 + 2 does not fit into integer type." - -SimpleCalculator.Calculate(2_147_483_647, 2, "*"); // => returns "The result of operation 2147483647 * 2 does not fit into integer type." -``` - -## 4. Handle the thrown DivideByZero exceptions +## 3. Handle the thrown DivideByZero exceptions When a `DivideByZeroException` exception gets thrown, the handling code should return the string with the content `Division by zero is not allowed.`. Any other exception should not be handled by the `SimpleCalculator.Calculate()` method. diff --git a/exercises/concept/calculator-conundrum/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md index 4e91c760dd..f8a9c5664f 100644 --- a/exercises/concept/calculator-conundrum/.docs/introduction.md +++ b/exercises/concept/calculator-conundrum/.docs/introduction.md @@ -4,7 +4,7 @@ Exceptions in C# provide a structured, uniform, and type-safe way of handling er In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown. -To signal that there should be an error in a certain part of the code, a new exception object needs to be created and then thrown,using the `throw` keyword: +To signal that there should be an error in a certain part of the code, a new exception object needs to be created and then thrown, using the `throw` keyword: ```csharp using System; @@ -18,29 +18,31 @@ static int Square(int number) } ``` -When an exception gets thrown, the runtime has the task of finding a piece of code that is responsible for handling of that exception. If no appropriate handler is found, the runtime displays the unhandled exception message in addition to stoping the execution of the program. To create a handler for an exception, C# uses the try-catch statement, which consists of a `try` block and one or more `catch` clauses. The `try` block should contain and guard code that may result in the exception getting thrown. The `catch` clauses should contain code that handles the behaviour of the program after the error has occured. It is important to note that the order of exceptions matters after the `try` block, as when multiple exceptions are listed, the first matching `catch` clause is executed. +When an exception gets thrown, the runtime has the task of finding a piece of code that is responsible for handling of that exception. If no appropriate handler is found, the runtime displays the unhandled exception message in addition to stopping the execution of the program. + +To create a handler for an exception, C# uses the try-catch statement, which consists of a `try` block and one or more `catch` clauses. The `try` block should contain and guard code that may result in the exception getting thrown. The `catch` clauses should contain code that handles the behavior of the program after the error has occurred. It is important to note that the order of exceptions matters after the `try` block, as when multiple exceptions are listed, the first matching `catch` clause is executed. ```csharp try { - if (number == -1) + if (number == 42) { - throw new ArgumentException("The number cannot be equal to -1", "number"); + throw new ArgumentException("The number cannot be equal to 42.", "number"); } if (number < 0) { - throw new ArgumentOutOfRangeException("number", "The number cannot be negative"); + throw new ArgumentOutOfRangeException("number", "The number cannot be negative."); } // Process number ... } catch (ArgumentOutOfRangeException e) { - Console.WriteLine($"Number is out of range: {e.Message}"); + Console.WriteLine($"Number is out of range: {e.Message}."); } catch (ArgumentException) { - Console.WriteLine($"Invalid number"); + Console.WriteLine("Invalid number."); } ``` diff --git a/exercises/concept/calculator-conundrum/.meta/Example.cs b/exercises/concept/calculator-conundrum/.meta/Example.cs index a6d71ba388..0657eb81a4 100644 --- a/exercises/concept/calculator-conundrum/.meta/Example.cs +++ b/exercises/concept/calculator-conundrum/.meta/Example.cs @@ -1,35 +1,32 @@ using System; -static class SimpleCalculator + +public static class SimpleCalculator { public static string Calculate(int operand1, int operand2, string operation) { - int result = 0; + int result; try { - switch(operation) + switch (operation) { case "+": - result = Calculator.Addition(operand1, operand2); + result = SimpleOperation.Addition(operand1, operand2); break; case "*": - result = Calculator.Multiplication(operand1, operand2); + result = SimpleOperation.Multiplication(operand1, operand2); break; case "/": - result = Calculator.Division(operand1, operand2); + result = SimpleOperation.Division(operand1, operand2); break; case "": - throw new ArgumentException("Operation cannot be empty.", operation); + throw new ArgumentException("Operation cannot be empty.", "operation"); case null: - throw new ArgumentNullException(operation, "Operation cannot be null."); + throw new ArgumentNullException("operation", "Operation cannot be null."); default: - throw new ArgumentOutOfRangeException(operation, $"Operation {operation} does not exist"); + throw new ArgumentOutOfRangeException("operation", $"Operation {operation} does not exist."); } } - catch(OverflowException) - { - return $"The result of operation {operand1} {operation} {operand2} does not fit into integer type."; - } - catch(DivideByZeroException) + catch (DivideByZeroException) { return "Division by zero is not allowed."; } @@ -38,7 +35,8 @@ public static string Calculate(int operand1, int operand2, string operation) } } -public static class Calculator +/**** Please do not modify the code below ****/ +public static class SimpleOperation { public static int Division(int operand1, int operand2) { @@ -47,16 +45,10 @@ public static int Division(int operand1, int operand2) public static int Multiplication(int operand1, int operand2) { - checked - { - return operand1 * operand2; - } + return operand1 * operand2; } public static int Addition(int operand1, int operand2) { - checked - { - return operand1 + operand2; - } + return operand1 + operand2; } -} \ No newline at end of file +} diff --git a/exercises/concept/calculator-conundrum/.meta/config.json b/exercises/concept/calculator-conundrum/.meta/config.json index 6eafd7d765..a5f95aabb7 100644 --- a/exercises/concept/calculator-conundrum/.meta/config.json +++ b/exercises/concept/calculator-conundrum/.meta/config.json @@ -1,5 +1,11 @@ { "contributors": [ + { + "github_username": "valentin-p", + "exercism_username": "valentin-p" + } + ], + "authors": [ { "github_username": "archrisV", "exercism_username": "archrisV" diff --git a/exercises/concept/calculator-conundrum/.meta/design.md b/exercises/concept/calculator-conundrum/.meta/design.md index 3c822196ba..3f6256dd9b 100644 --- a/exercises/concept/calculator-conundrum/.meta/design.md +++ b/exercises/concept/calculator-conundrum/.meta/design.md @@ -14,8 +14,9 @@ The goal of this exercise is to teach the student the Concept of Exceptions in C - Exception filters. - User-defined exceptions. -- try/finally blocks +- try/finally blocks. - Memory and performance characteristics. +- Overflows. ## Concepts @@ -26,7 +27,6 @@ The goal of this exercise is to teach the student the Concept of Exceptions in C - `basics`: know how to do string interpolation and how to work with `int`s - `inheritance`: know about class hierarchies - `nullability`: know what `null` is -- `overflows`: know what an `OverflowException` is - `switch-statements`: know how to write a `switch` statement ## Resources to refer to diff --git a/exercises/concept/calculator-conundrum/CalculatorConundrum.cs b/exercises/concept/calculator-conundrum/CalculatorConundrum.cs index 25a614250b..812715cda9 100644 --- a/exercises/concept/calculator-conundrum/CalculatorConundrum.cs +++ b/exercises/concept/calculator-conundrum/CalculatorConundrum.cs @@ -1,12 +1,15 @@ using System; -static class SimpleCalculator + +public static class SimpleCalculator { public static string Calculate(int operand1, int operand2, string operation) { - throw new NotImplementedException(); + throw new NotImplementedException("Please implement the SimpleCalculator.Calculate() method"); } +} -public static class Calculator +/**** Please do not modify the code below ****/ +public static class SimpleOperation { public static int Division(int operand1, int operand2) { @@ -15,16 +18,10 @@ public static int Division(int operand1, int operand2) public static int Multiplication(int operand1, int operand2) { - checked - { - return operand1 * operand2; - } + return operand1 * operand2; } public static int Addition(int operand1, int operand2) { - checked - { - return operand1 + operand2; - } + return operand1 + operand2; } -} \ No newline at end of file +} diff --git a/exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs b/exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs index d8a841729c..6531c7946c 100644 --- a/exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs +++ b/exercises/concept/calculator-conundrum/CalculatorConundrumTests.cs @@ -1,5 +1,6 @@ using Xunit; using System; + public class SimpleCalculatorTests { //Addition tests @@ -15,12 +16,6 @@ public void Addition_with_large_operands() Assert.Equal("378961 + 399635 = 778596", SimpleCalculator.Calculate(378_961, 399_635, "+")); } - [Fact(Skip = "Remove this Skip property to run this test")] - public void Addition_that_overflows() - { - Assert.Equal("The result of operation 2147483647 + 5 does not fit into integer type.", SimpleCalculator.Calculate(Int32.MaxValue, 5, "+")); - } - //Multiplication tests [Fact(Skip = "Remove this Skip property to run this test")] public void Multiplication_with_small_operands() @@ -34,12 +29,6 @@ public void Multiplication_with_large_operands() Assert.Equal("72441 * 2048 = 148359168", SimpleCalculator.Calculate(72_441, 2_048, "*")); } - [Fact(Skip = "Remove this Skip property to run this test")] - public void Multiplication_that_overflows() - { - Assert.Equal("The result of operation 50000 * 50000 does not fit into integer type.", SimpleCalculator.Calculate(50_000, 50_000, "*")); - } - //Division tests [Fact(Skip = "Remove this Skip property to run this test")] public void Division_with_small_operands() @@ -56,7 +45,7 @@ public void Division_with_large_operands() [Fact(Skip = "Remove this Skip property to run this test")] public void Calculate_throws_exception_for_division_with_0() { - Assert.Equal("Division by zero is not allowed.", SimpleCalculator.Calculate(33, 0, "/")); + Assert.Equal("Division by zero is not allowed.", SimpleCalculator.Calculate(33, 0, "/")); } // Invalid operator @@ -65,7 +54,7 @@ public void Calculate_throws_exception_for_non_valid_operations() { Assert.Throws(() => SimpleCalculator.Calculate(1, 2, "**")); } - + [Fact(Skip = "Remove this Skip property to run this test")] public void Calculate_throws_exception_for_null_as_operation() { @@ -73,8 +62,8 @@ public void Calculate_throws_exception_for_null_as_operation() } [Fact(Skip = "Remove this Skip property to run this test")] - public void Calculate_throws_exception_for_emtpy_string_as_operation() + public void Calculate_throws_exception_for_empty_string_as_operation() { Assert.Throws(() => SimpleCalculator.Calculate(1, 2, "")); } -} \ No newline at end of file +} From 61e5a0cef4329b6332c421c8b17845e058a38477 Mon Sep 17 00:00:00 2001 From: Erik Schierboom Date: Wed, 11 Nov 2020 15:03:25 +0100 Subject: [PATCH 266/327] Add description of concept documents [Docs] Add description of concept documents Co-authored-by: Jeremy Walker --- concepts/equality/about.md | 2 +- .../authentication-system/.meta/design.md | 2 +- .../lucians-luscious-lasagna/.meta/design.md | 2 +- .../concept/weighing-machine/.meta/design.md | 18 +++++------------- reference/implementing-a-concept-exercise.md | 10 +++++++--- 5 files changed, 15 insertions(+), 19 deletions(-) diff --git a/concepts/equality/about.md b/concepts/equality/about.md index 0c9e858ea9..2895dd239a 100644 --- a/concepts/equality/about.md +++ b/concepts/equality/about.md @@ -117,7 +117,7 @@ If only one hashed collection is in play then it may be better to avoid `IEquali ### Note on floating-point equality -One primitive that can challenge the unwary coder is testing the [equality of floating-point values][0.30000000000000004.com]. This is discussed in the _after.md_ document for the `floating-point-numbers` exercise. +One primitive that can challenge the unwary coder is testing the [equality of floating-point values][0.30000000000000004.com]. This is discussed in the _about.md_ document for the `floating-point-numbers` concept. ### Equality and Inheritance diff --git a/exercises/concept/authentication-system/.meta/design.md b/exercises/concept/authentication-system/.meta/design.md index 1249ec00b6..f8f727edbe 100644 --- a/exercises/concept/authentication-system/.meta/design.md +++ b/exercises/concept/authentication-system/.meta/design.md @@ -24,7 +24,7 @@ - `classes`: know how to define fields. - `basics`: know how to define variables. - `object-initializers`: part of the provided code -- `arrays`: referred to in _after.md_ +- `arrays`: referred to in _about.md_ - `properties`: understand how accessors are independent of each other - `dictionaries`: understand the syntax and semantics of dictionaries (incl. in code) - `nested-types`: understand the syntax of semantics nested types (incl. in code) diff --git a/exercises/concept/lucians-luscious-lasagna/.meta/design.md b/exercises/concept/lucians-luscious-lasagna/.meta/design.md index 36242ae0eb..860e6014d1 100644 --- a/exercises/concept/lucians-luscious-lasagna/.meta/design.md +++ b/exercises/concept/lucians-luscious-lasagna/.meta/design.md @@ -9,7 +9,7 @@ - Know how to call a method - Know that methods must be defined in classes - Know about the `public` access modifier -- Know about the `static` modifier (only in `after.md`) +- Know about the `static` modifier (only in concept's `about.md`) - Know how to define an integer - Know how to use mathematical operators on integers - Know how to define single- and multiline comments diff --git a/exercises/concept/weighing-machine/.meta/design.md b/exercises/concept/weighing-machine/.meta/design.md index afb1ab6f44..f52ac0d9f7 100644 --- a/exercises/concept/weighing-machine/.meta/design.md +++ b/exercises/concept/weighing-machine/.meta/design.md @@ -112,7 +112,6 @@ languages └── concept └── properties ├── .docs - | ├── after.md | ├── hints.md | ├── instructions.md | └── introduction.md @@ -136,13 +135,7 @@ This file contains instructions for the exercise. It should explicitly explain w If the user gets stuck, we will allow them to click a button requesting a hint, which shows this file. We will softly discourage them using it. The file should contain both general and task-specific "hints". These hints should be enough to unblock almost any student. -## Step 4: add .docs/after.md - -Once the user completes the exercise they will be shown this file, which gives them any bonus information or further reading about the concept taught. - -These files are also all described in the [concept exercises document][docs-concept-exercises]. - -## Step 5: update languages/csharp/config.json +## Step 4: update languages/csharp/config.json An entry should be added to the track's `config.json` file for the new concept exercise: @@ -169,7 +162,7 @@ An entry should be added to the track's `config.json` file for the new concept e } ``` -## Step 6: adding track-specific files +## Step 5: adding track-specific files These files are specific to the C# track: @@ -180,15 +173,15 @@ These files are specific to the C# track: Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-numbers-floating-point] for an example on what these files should look like. -## Step 7: update the general concept document +## Step 6: update the general concept document Not applicable for this concept -## Step 8: updating list of implemented exercises +## Step 7: updating list of implemented exercises - Add the exercise to the [list of implemented exercises][csharp-docs-concept-exercises]. -## Step 9: add .meta/design.md: +## Step 8: add .meta/design.md: This file contains information on the exercise's design, which includes things like its goal, its teaching goals, what not to teach, and more ([example][meta-design]). This information can be extracted from this GitHub issue. @@ -212,7 +205,6 @@ When implementing this exericse, it can be very useful to look at already implem [csharp-representer]: https://github.com/exercism/csharp-representer [csharp-docs-cli.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/cli.md [csharp-docs-debug.md]: https://github.com/exercism/v3/blob/master/languages/csharp/exercises/.docs/debug.md -[csharp-docs-after.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/after.md [csharp-docs-hints.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/hints.md [csharp-docs-introduction.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/introduction.md [csharp-docs-instructions.md]: https://github.com/exercism/v3/blob/master/interest-is-interesting/.docs/instructions.md diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md index 773d0c60c1..99a5d0a9e5 100644 --- a/reference/implementing-a-concept-exercise.md +++ b/reference/implementing-a-concept-exercise.md @@ -14,8 +14,9 @@ Please also watch the following video: As this document is generic, the following placeholders are used: -- ``: the name of the exercise in kebab-case (e.g. `anonymous-methods`). -- ``: the name of the exercise in PascalCase (e.g. `AnonymousMethods`). +- ``: the slug of the exercise in kebab-case (e.g. `calculator-conundrum`). +- ``: the name of the exercise in PascalCase (e.g. `CalculatorConundrum`). +- ``: the slug of one of the exercise's concepts in kebab-case (e.g. `anonymous-methods`). Before implementing the exercise, please make sure you have a good understanding of what the exercise should be teaching (and what not). This information can be found in the exercise's GitHub issue. Having done this, please read the [C# concept exercises introduction][concept-exercises]. @@ -24,11 +25,14 @@ To implement a concept exercise, the following files must be added:
 languages
 └── csharp
+    ├── concepts
+    |   └── <CONCEPT_SLUG>
+    |       ├── about.md
+    |       └── links.json
     └── exercises
         └── concept
             └── <SLUG>
                 ├── .docs
-                |   ├── after.md
                 |   ├── instructions.md
                 |   ├── introduction.md
                 |   ├── hints.md

From 8c982421c8d58a801416031dbcb6304b4e7d417e Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Wed, 11 Nov 2020 16:19:27 +0100
Subject: [PATCH 267/327] Fix package versions

---
 .../concept/annalyns-infiltration/AnnalynsInfiltration.csproj | 4 ++--
 .../concept/attack-of-the-trolls/AttackOfTheTrolls.csproj     | 4 ++--
 .../concept/authentication-system/AuthenticationSystem.csproj | 2 +-
 .../beauty-salon-goes-global/BeautySalonGoesGlobal.csproj     | 2 +-
 exercises/concept/bird-watcher/BirdWatcher.csproj             | 4 ++--
 .../concept/booking-up-for-beauty/BookingUpForBeauty.csproj   | 4 ++--
 exercises/concept/building-telemetry/BuildingTelemetry.csproj | 2 +-
 .../concept/calculator-conundrum/CalculatorConundrum.csproj   | 2 +-
 exercises/concept/cars-assemble/CarsAssemble.csproj           | 4 ++--
 exercises/concept/elons-toys/ElonsToys.csproj                 | 4 ++--
 exercises/concept/faceid-2/Faceid2.csproj                     | 2 +-
 .../football-match-reports/FootballMatchReports.csproj        | 2 +-
 .../high-school-sweethearts/HighSchoolSweethearts.csproj      | 2 +-
 .../hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj  | 2 +-
 exercises/concept/hyperia-forex/HyperiaForex.csproj           | 2 +-
 .../HyperinflationHitsHyperia.csproj                          | 2 +-
 .../concept/instruments-of-texas/InstrumentsOfTexas.csproj    | 2 +-
 .../interest-is-interesting/InterestIsInteresting.csproj      | 4 ++--
 .../InternationalCallingConnoisseur.csproj                    | 2 +-
 exercises/concept/land-grab-in-space/LandGrabInSpace.csproj   | 2 +-
 exercises/concept/log-levels/LogLevels.csproj                 | 4 ++--
 exercises/concept/logs-logs-logs/LogsLogsLogs.csproj          | 4 ++--
 .../lucians-luscious-lasagna/LuciansLusciousLasagna.csproj    | 4 ++--
 exercises/concept/need-for-speed/NeedForSpeed.csproj          | 4 ++--
 .../object-relational-mapping/ObjectRelationalMapping.csproj  | 2 +-
 exercises/concept/orm-in-one-go/OrmInOneGo.csproj             | 2 +-
 exercises/concept/parsing-log-files/ParsingLogFiles.csproj    | 2 +-
 .../concept/phone-number-analysis/PhoneNumberAnalysis.csproj  | 2 +-
 .../red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj      | 2 +-
 .../remote-control-cleanup/RemoteControlCleanup.csproj        | 2 +-
 .../RemoteControlCompetition.csproj                           | 2 +-
 exercises/concept/roll-the-die/RollTheDie.csproj              | 2 +-
 .../secure-munchester-united/SecureMunchesterUnited.csproj    | 2 +-
 exercises/concept/squeaky-clean/SqueakyClean.csproj           | 2 +-
 .../concept/the-weather-in-deather/TheWeatherInDeather.csproj | 2 +-
 exercises/concept/tim-from-marketing/TimFromMarketing.csproj  | 4 ++--
 .../tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj  | 2 +-
 exercises/concept/weighing-machine/WeighingMachine.csproj     | 2 +-
 .../concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj | 2 +-
 .../concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj | 4 ++--
 .../concept/wizards-and-warriors/WizardsAndWarriors.csproj    | 4 ++--
 41 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
+++ b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
+++ b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/authentication-system/AuthenticationSystem.csproj b/exercises/concept/authentication-system/AuthenticationSystem.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/authentication-system/AuthenticationSystem.csproj
+++ b/exercises/concept/authentication-system/AuthenticationSystem.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
+++ b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/bird-watcher/BirdWatcher.csproj b/exercises/concept/bird-watcher/BirdWatcher.csproj
index 6769a865d6..406670a433 100644
--- a/exercises/concept/bird-watcher/BirdWatcher.csproj
+++ b/exercises/concept/bird-watcher/BirdWatcher.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
diff --git a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
+++ b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/building-telemetry/BuildingTelemetry.csproj b/exercises/concept/building-telemetry/BuildingTelemetry.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/building-telemetry/BuildingTelemetry.csproj
+++ b/exercises/concept/building-telemetry/BuildingTelemetry.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj b/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
index 0d9d54e3f8..994118ac7c 100644
--- a/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
+++ b/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
@@ -7,7 +7,7 @@
   
     
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/cars-assemble/CarsAssemble.csproj b/exercises/concept/cars-assemble/CarsAssemble.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/cars-assemble/CarsAssemble.csproj
+++ b/exercises/concept/cars-assemble/CarsAssemble.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/elons-toys/ElonsToys.csproj b/exercises/concept/elons-toys/ElonsToys.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/elons-toys/ElonsToys.csproj
+++ b/exercises/concept/elons-toys/ElonsToys.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/faceid-2/Faceid2.csproj b/exercises/concept/faceid-2/Faceid2.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/faceid-2/Faceid2.csproj
+++ b/exercises/concept/faceid-2/Faceid2.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/football-match-reports/FootballMatchReports.csproj b/exercises/concept/football-match-reports/FootballMatchReports.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/football-match-reports/FootballMatchReports.csproj
+++ b/exercises/concept/football-match-reports/FootballMatchReports.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
+++ b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
+++ b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/hyperia-forex/HyperiaForex.csproj b/exercises/concept/hyperia-forex/HyperiaForex.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/hyperia-forex/HyperiaForex.csproj
+++ b/exercises/concept/hyperia-forex/HyperiaForex.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
+++ b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
+++ b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
+++ b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
+++ b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj b/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
+++ b/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/log-levels/LogLevels.csproj b/exercises/concept/log-levels/LogLevels.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/log-levels/LogLevels.csproj
+++ b/exercises/concept/log-levels/LogLevels.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
+++ b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
+++ b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/need-for-speed/NeedForSpeed.csproj b/exercises/concept/need-for-speed/NeedForSpeed.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/need-for-speed/NeedForSpeed.csproj
+++ b/exercises/concept/need-for-speed/NeedForSpeed.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
+++ b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/orm-in-one-go/OrmInOneGo.csproj b/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
+++ b/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/parsing-log-files/ParsingLogFiles.csproj b/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
+++ b/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
index 74c13b2836..9d564eb080 100644
--- a/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
+++ b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
@@ -7,7 +7,7 @@
     
         
         
-        
+        
     
 
 
diff --git a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
+++ b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
+++ b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj b/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
+++ b/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/roll-the-die/RollTheDie.csproj b/exercises/concept/roll-the-die/RollTheDie.csproj
index 206cf24cce..1caa073a6f 100644
--- a/exercises/concept/roll-the-die/RollTheDie.csproj
+++ b/exercises/concept/roll-the-die/RollTheDie.csproj
@@ -8,7 +8,7 @@
         
         
         
-        
+        
     
 
 
diff --git a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
+++ b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/squeaky-clean/SqueakyClean.csproj b/exercises/concept/squeaky-clean/SqueakyClean.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/squeaky-clean/SqueakyClean.csproj
+++ b/exercises/concept/squeaky-clean/SqueakyClean.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
+++ b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
index 2583c2317b..1964bbeb6d 100644
--- a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
+++ b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
@@ -6,9 +6,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
+++ b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/weighing-machine/WeighingMachine.csproj b/exercises/concept/weighing-machine/WeighingMachine.csproj
index dbeb9f05e3..8ed0349d0a 100644
--- a/exercises/concept/weighing-machine/WeighingMachine.csproj
+++ b/exercises/concept/weighing-machine/WeighingMachine.csproj
@@ -7,7 +7,7 @@
     
         
         
-        
+        
     
 
 
diff --git a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
index e7a827a208..114c7a6c39 100644
--- a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
+++ b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
@@ -7,7 +7,7 @@
     
       
       
-      
+      
     
 
 
diff --git a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
+++ b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file
diff --git a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
index 8d66e73a50..7ea9f8571c 100644
--- a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
+++ b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
@@ -5,9 +5,9 @@
   
 
   
-    
+    
     
-    
+    
   
 
 
\ No newline at end of file

From ca7ae4e8ac95fffa5fe133e93aed7f6a18d90805 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Thu, 12 Nov 2020 14:51:28 +0100
Subject: [PATCH 268/327] replace conditionals with if-statements

* replace if-statements with conditionals
---
 concepts/if-statements/about.md                           | 4 ++++
 concepts/if-statements/links.json                         | 7 ++++++-
 exercises/concept/bird-watcher/.meta/design.md            | 2 +-
 exercises/concept/interest-is-interesting/.meta/design.md | 3 +--
 exercises/concept/squeaky-clean/.meta/design.md           | 4 ++--
 reference/exercise-concepts/isbn-verifier.md              | 2 +-
 reference/exercise-concepts/rna-trascriptions.md          | 2 +-
 reference/exercise-concepts/robot-name.md                 | 2 +-
 8 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/concepts/if-statements/about.md b/concepts/if-statements/about.md
index e256153118..e5a4365d41 100644
--- a/concepts/if-statements/about.md
+++ b/concepts/if-statements/about.md
@@ -1,5 +1,7 @@
 An `if` statement can be used to conditionally execute code. The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values.
 
+The most common way to do this in C# is by using [an `if/else` statement][if-else]:
+
 ```csharp
 int x = 6;
 
@@ -16,3 +18,5 @@ else
     // Execute logic in all other cases
 }
 ```
+
+[if-else]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else
diff --git a/concepts/if-statements/links.json b/concepts/if-statements/links.json
index fe51488c70..00e7879d8b 100644
--- a/concepts/if-statements/links.json
+++ b/concepts/if-statements/links.json
@@ -1 +1,6 @@
-[]
+[
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/if-else",
+    "description": "if-else"
+  }
+]
diff --git a/exercises/concept/bird-watcher/.meta/design.md b/exercises/concept/bird-watcher/.meta/design.md
index 4e5c49c4a5..a41caebea1 100644
--- a/exercises/concept/bird-watcher/.meta/design.md
+++ b/exercises/concept/bird-watcher/.meta/design.md
@@ -35,4 +35,4 @@ This exercise's prerequisites Concepts are:
 - `classes`: know how to work with fields.
 - `booleans`: know what a `bool` is.
 - `basics`: know how to work with `integers` and how to assign and update variables.
-- `if-statements`:
+- `if-statements`: know how to do conditional logic.
diff --git a/exercises/concept/interest-is-interesting/.meta/design.md b/exercises/concept/interest-is-interesting/.meta/design.md
index 6962fb50c2..9ecb39352b 100644
--- a/exercises/concept/interest-is-interesting/.meta/design.md
+++ b/exercises/concept/interest-is-interesting/.meta/design.md
@@ -22,7 +22,6 @@
 This exercise's prerequisites Concepts are:
 
 - `numbers`: define numbers and apply arithmetic and boolean logic to them.
-- `conditionals`: conditionally execute code based on value of floating-point numbers.
-- `if-statements`:
+- `if-statements`: conditionally execute code based on value of floating-point numbers.
 
 [docs.microsoft.com-floating-point-numeric-types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types
diff --git a/exercises/concept/squeaky-clean/.meta/design.md b/exercises/concept/squeaky-clean/.meta/design.md
index 848db58daf..1128c7d39f 100644
--- a/exercises/concept/squeaky-clean/.meta/design.md
+++ b/exercises/concept/squeaky-clean/.meta/design.md
@@ -25,5 +25,5 @@
 ## Prerequisites
 
 - `strings`: know of the `string` type that will be iterated over and accessed by index.
-- `for-loop` for loops (rather than foreach) are the best means of highlighting the relationship between strings and `char`s
-- `if-statements`:
+- `for-loops`: for loops (rather than foreach) are the best means of highlighting the relationship between strings and `char`s
+- `if-statements`: know how to do conditional logic.
diff --git a/reference/exercise-concepts/isbn-verifier.md b/reference/exercise-concepts/isbn-verifier.md
index e225fda70e..feda0133dc 100644
--- a/reference/exercise-concepts/isbn-verifier.md
+++ b/reference/exercise-concepts/isbn-verifier.md
@@ -13,7 +13,7 @@
 - strings: used to store the isbn numbers
 - for loop: iterate over the numbers to check if valid
 - conditionals: used for checking values
-- ternary operator: combine conditonals to check for isbn
+- ternary operator: combine conditionals to check for isbn
 - assignment: assigning values to variables
 - type inference: using var to define variables
 - math operators: `++` and `--` used to increment counts in loop, modulus operator
diff --git a/reference/exercise-concepts/rna-trascriptions.md b/reference/exercise-concepts/rna-trascriptions.md
index 5957f33fab..c2c28de139 100644
--- a/reference/exercise-concepts/rna-trascriptions.md
+++ b/reference/exercise-concepts/rna-trascriptions.md
@@ -33,7 +33,7 @@
 
 ## Types
 
-- strings: the basis of the exercice. I think things like Concat/Join/+/StringBuilder/ToString are problably concepts by themselves.
+- strings: the basis of the exercise. I think things like Concat/Join/+/StringBuilder/ToString are probably concepts by themselves.
 - lists: used as intermediate data structure.
 - dictionaries: used to store pre computed RNA pairs.
 - arrays: used as intermediate data structure.
diff --git a/reference/exercise-concepts/robot-name.md b/reference/exercise-concepts/robot-name.md
index 1782492b68..0e26fe1e34 100644
--- a/reference/exercise-concepts/robot-name.md
+++ b/reference/exercise-concepts/robot-name.md
@@ -5,7 +5,7 @@
 ## General
 
 - functions: used as the main entry point to this exercise
-- constructors: initalizing values when object is created
+- constructors: initializing values when object is created
 - conditionals using if: conditionally execute logic using an `if` statement
 - classes: the tested method is defined in a class
 - objects: creating an object to keep track of the robot

From 1ec8fd740cc46a270605eb2d4a30d73ca760726d Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 17 Nov 2020 07:38:09 +0100
Subject: [PATCH 269/327] Upgrade to .NET 5

---
 .../concept/annalyns-infiltration/AnnalynsInfiltration.csproj | 4 ++--
 .../concept/attack-of-the-trolls/AttackOfTheTrolls.csproj     | 4 ++--
 .../concept/authentication-system/AuthenticationSystem.csproj | 2 +-
 .../beauty-salon-goes-global/BeautySalonGoesGlobal.csproj     | 2 +-
 exercises/concept/bird-watcher/BirdWatcher.csproj             | 4 ++--
 .../concept/booking-up-for-beauty/BookingUpForBeauty.csproj   | 4 ++--
 exercises/concept/building-telemetry/BuildingTelemetry.csproj | 2 +-
 .../concept/calculator-conundrum/CalculatorConundrum.csproj   | 2 +-
 exercises/concept/cars-assemble/CarsAssemble.csproj           | 4 ++--
 exercises/concept/elons-toys/ElonsToys.csproj                 | 4 ++--
 exercises/concept/faceid-2/Faceid2.csproj                     | 2 +-
 .../football-match-reports/FootballMatchReports.csproj        | 2 +-
 .../high-school-sweethearts/HighSchoolSweethearts.csproj      | 2 +-
 .../hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj  | 2 +-
 exercises/concept/hyperia-forex/HyperiaForex.csproj           | 2 +-
 .../HyperinflationHitsHyperia.csproj                          | 2 +-
 .../concept/instruments-of-texas/InstrumentsOfTexas.csproj    | 2 +-
 .../interest-is-interesting/InterestIsInteresting.csproj      | 4 ++--
 .../InternationalCallingConnoisseur.csproj                    | 2 +-
 exercises/concept/land-grab-in-space/LandGrabInSpace.csproj   | 2 +-
 exercises/concept/log-levels/LogLevels.csproj                 | 4 ++--
 exercises/concept/logs-logs-logs/LogsLogsLogs.csproj          | 4 ++--
 .../lucians-luscious-lasagna/LuciansLusciousLasagna.csproj    | 4 ++--
 exercises/concept/need-for-speed/NeedForSpeed.csproj          | 4 ++--
 .../object-relational-mapping/ObjectRelationalMapping.csproj  | 2 +-
 exercises/concept/orm-in-one-go/OrmInOneGo.csproj             | 2 +-
 exercises/concept/parsing-log-files/ParsingLogFiles.csproj    | 2 +-
 .../concept/phone-number-analysis/PhoneNumberAnalysis.csproj  | 2 +-
 .../red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj      | 2 +-
 .../remote-control-cleanup/RemoteControlCleanup.csproj        | 2 +-
 .../RemoteControlCompetition.csproj                           | 2 +-
 exercises/concept/roll-the-die/RollTheDie.csproj              | 2 +-
 .../secure-munchester-united/SecureMunchesterUnited.csproj    | 2 +-
 exercises/concept/squeaky-clean/SqueakyClean.csproj           | 2 +-
 .../concept/the-weather-in-deather/TheWeatherInDeather.csproj | 2 +-
 exercises/concept/tim-from-marketing/TimFromMarketing.csproj  | 4 ++--
 .../tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj  | 2 +-
 exercises/concept/weighing-machine/WeighingMachine.csproj     | 2 +-
 .../concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj | 2 +-
 .../concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj | 4 ++--
 .../concept/wizards-and-warriors/WizardsAndWarriors.csproj    | 4 ++--
 41 files changed, 55 insertions(+), 55 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
+++ b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
+++ b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/authentication-system/AuthenticationSystem.csproj b/exercises/concept/authentication-system/AuthenticationSystem.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/authentication-system/AuthenticationSystem.csproj
+++ b/exercises/concept/authentication-system/AuthenticationSystem.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
+++ b/exercises/concept/beauty-salon-goes-global/BeautySalonGoesGlobal.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/bird-watcher/BirdWatcher.csproj b/exercises/concept/bird-watcher/BirdWatcher.csproj
index 406670a433..7965bd0632 100644
--- a/exercises/concept/bird-watcher/BirdWatcher.csproj
+++ b/exercises/concept/bird-watcher/BirdWatcher.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
+++ b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/building-telemetry/BuildingTelemetry.csproj b/exercises/concept/building-telemetry/BuildingTelemetry.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/building-telemetry/BuildingTelemetry.csproj
+++ b/exercises/concept/building-telemetry/BuildingTelemetry.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj b/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
index 994118ac7c..8f1577a176 100644
--- a/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
+++ b/exercises/concept/calculator-conundrum/CalculatorConundrum.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
diff --git a/exercises/concept/cars-assemble/CarsAssemble.csproj b/exercises/concept/cars-assemble/CarsAssemble.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/cars-assemble/CarsAssemble.csproj
+++ b/exercises/concept/cars-assemble/CarsAssemble.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/elons-toys/ElonsToys.csproj b/exercises/concept/elons-toys/ElonsToys.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/elons-toys/ElonsToys.csproj
+++ b/exercises/concept/elons-toys/ElonsToys.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/faceid-2/Faceid2.csproj b/exercises/concept/faceid-2/Faceid2.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/faceid-2/Faceid2.csproj
+++ b/exercises/concept/faceid-2/Faceid2.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/football-match-reports/FootballMatchReports.csproj b/exercises/concept/football-match-reports/FootballMatchReports.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/football-match-reports/FootballMatchReports.csproj
+++ b/exercises/concept/football-match-reports/FootballMatchReports.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
+++ b/exercises/concept/high-school-sweethearts/HighSchoolSweethearts.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
+++ b/exercises/concept/hyper-optimized-telemetry/HyperOptimizedTelemetry.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/hyperia-forex/HyperiaForex.csproj b/exercises/concept/hyperia-forex/HyperiaForex.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/hyperia-forex/HyperiaForex.csproj
+++ b/exercises/concept/hyperia-forex/HyperiaForex.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
+++ b/exercises/concept/hyperinflation-hits-hyperia/HyperinflationHitsHyperia.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
+++ b/exercises/concept/instruments-of-texas/InstrumentsOfTexas.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
+++ b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
+++ b/exercises/concept/international-calling-connoisseur/InternationalCallingConnoisseur.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj b/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
+++ b/exercises/concept/land-grab-in-space/LandGrabInSpace.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/log-levels/LogLevels.csproj b/exercises/concept/log-levels/LogLevels.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/log-levels/LogLevels.csproj
+++ b/exercises/concept/log-levels/LogLevels.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
+++ b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
+++ b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/need-for-speed/NeedForSpeed.csproj b/exercises/concept/need-for-speed/NeedForSpeed.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/need-for-speed/NeedForSpeed.csproj
+++ b/exercises/concept/need-for-speed/NeedForSpeed.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
+++ b/exercises/concept/object-relational-mapping/ObjectRelationalMapping.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/orm-in-one-go/OrmInOneGo.csproj b/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
+++ b/exercises/concept/orm-in-one-go/OrmInOneGo.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/parsing-log-files/ParsingLogFiles.csproj b/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
+++ b/exercises/concept/parsing-log-files/ParsingLogFiles.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
index 9d564eb080..dcda93dd44 100644
--- a/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
+++ b/exercises/concept/phone-number-analysis/PhoneNumberAnalysis.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
+++ b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
+++ b/exercises/concept/remote-control-cleanup/RemoteControlCleanup.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj b/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
+++ b/exercises/concept/remote-control-competition/RemoteControlCompetition.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/roll-the-die/RollTheDie.csproj b/exercises/concept/roll-the-die/RollTheDie.csproj
index 1caa073a6f..0c17bd4f8e 100644
--- a/exercises/concept/roll-the-die/RollTheDie.csproj
+++ b/exercises/concept/roll-the-die/RollTheDie.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
+++ b/exercises/concept/secure-munchester-united/SecureMunchesterUnited.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/squeaky-clean/SqueakyClean.csproj b/exercises/concept/squeaky-clean/SqueakyClean.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/squeaky-clean/SqueakyClean.csproj
+++ b/exercises/concept/squeaky-clean/SqueakyClean.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
+++ b/exercises/concept/the-weather-in-deather/TheWeatherInDeather.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
index 1964bbeb6d..fead1729ca 100644
--- a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
+++ b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
@@ -1,12 +1,12 @@
 
 
   
-    netcoreapp3.1
+    net5.0
     enable
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
+++ b/exercises/concept/tracks-on-tracks-on-tracks/TracksOnTracksOnTracks.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/weighing-machine/WeighingMachine.csproj b/exercises/concept/weighing-machine/WeighingMachine.csproj
index 8ed0349d0a..a490145f54 100644
--- a/exercises/concept/weighing-machine/WeighingMachine.csproj
+++ b/exercises/concept/weighing-machine/WeighingMachine.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
index 114c7a6c39..b594edc84f 100644
--- a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
+++ b/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
@@ -1,7 +1,7 @@
 
 
     
-        netcoreapp3.1
+        net5.0
     
 
     
diff --git a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
+++ b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
index 7ea9f8571c..008d1fa438 100644
--- a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
+++ b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
@@ -1,11 +1,11 @@
 
 
   
-    netcoreapp3.1
+    net5.0
   
 
   
-    
+    
     
     
   

From f401944b81913dba3f91da0da0436dd9cfcc7c18 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Tue, 17 Nov 2020 08:00:36 +0100
Subject: [PATCH 270/327] Basics concept. detailing variable names

Basics - link to name identifier
---
 concepts/basics/about.md   |  7 ++++++-
 concepts/basics/links.json | 12 ++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/concepts/basics/about.md b/concepts/basics/about.md
index 343febaddd..6748f22a9e 100644
--- a/concepts/basics/about.md
+++ b/concepts/basics/about.md
@@ -1,4 +1,4 @@
-C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value.
+C# is a statically-typed language, which means that everything has a type at compile-time. Choosing a name for a variable is referred to as defining a variable. Once a variable is defined, setting or updating a value is called variable assignment. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value.
 
 ```csharp
 int explicitVar = 10; // Explicitly typed
@@ -70,6 +70,8 @@ C# supports two types of [comments][comments]. Single line comments are preceded
 
 Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators].
 
+A variable name [must follow some rules][identifier-names] like starting either by a letter or an underscore, and [should follow C# naming convention][naming-guidelines]. If a variable name collides with a reserved [C# keyword][csharp-keywords], it must be escaped using `@`. It is not recommended to use that notation, but it can be encountered in exceptional cases, for example: `var @this`, `var @class` or `var @var`.
+
 [assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator
 [var]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var
 [classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/classes#declaring-classes
@@ -77,3 +79,6 @@ Integer values are defined as one or more (consecutive) digits and support the [
 [return]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/return
 [operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator-
 [comments]: https://www.w3schools.com/cs/cs_comments.asp
+[identifier-names]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names
+[naming-guidelines]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines
+[csharp-keywords]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
diff --git a/concepts/basics/links.json b/concepts/basics/links.json
index b26b0bf896..a650962628 100644
--- a/concepts/basics/links.json
+++ b/concepts/basics/links.json
@@ -26,5 +26,17 @@
   {
     "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/arithmetic-operators#addition-operator-",
     "description": "operators"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names",
+    "description": "variable-names"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines",
+    "description": "naming-guidelines"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/",
+    "description": "csharp-keywords"
   }
 ]

From bc8529c8e979b702c9b93a60f03eadd74914c9e2 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Tue, 17 Nov 2020 09:35:48 +0100
Subject: [PATCH 271/327] Namespace concept. Red vs Blue. Tests

Add tests except for using alias
---
 .../red-vs-blue-darwin-style/.meta/Example.cs |  1 -
 .../.meta/config.json                         |  4 ++
 .../RedVsBlueDarwinStyle.cs                   |  2 +-
 .../RedVsBlueDarwinStyleTests.cs              | 51 +++++++++++++++++--
 4 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs b/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs
index e91ef4ccf5..386d4030ab 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs
+++ b/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs
@@ -35,7 +35,6 @@ public class RemoteControlCar
     {
         public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry)
         {
-
         }
         // blue members and API
     }
diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/config.json b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
index 74b4c034b6..9092ce1688 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
+++ b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
@@ -3,6 +3,10 @@
     {
       "github_username": "ErikSchierboom",
       "exercism_username": "ErikSchierboom"
+    },
+    {
+      "github_username": "valentin-p",
+      "exercism_username": "valentin-p"
     }
   ],
   "authors": [
diff --git a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs
index 36970f2861..bebff6bda0 100644
--- a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs
+++ b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyle.cs
@@ -28,13 +28,13 @@ public class Motor
         // red members and API
     }
 }
+
 public static class BlueRemoteControlCarTeam
 {
     public class RemoteControlCar
     {
         public RemoteControlCar(Motor motor, Chassis chassis, Telemetry telemetry)
         {
-
         }
         // blue members and API
     }
diff --git a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs
index 5a33bb4b1a..3c31bc2266 100644
--- a/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs
+++ b/exercises/concept/red-vs-blue-darwin-style/RedVsBlueDarwinStyleTests.cs
@@ -1,17 +1,58 @@
-using Combined;
+using System;
 using Xunit;
 
 public class NamespacesTests
 {
     [Fact]
-    public void BuildRed()
+    public void Namespace_for_CarBuilder_is_Combined()
     {
-        Assert.NotNull(CarBuilder.BuildRed());
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        Assert.NotNull(carBuilderType);
     }
 
     [Fact(Skip = "Remove this Skip property to run this test")]
-    public void BuildBlue()
+    public void Namespace_for_CarBuilder_has_method_BuildBlue()
     {
-        Assert.NotNull(CarBuilder.BuildBlue());
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        Assert.NotNull(carBuilderType?.GetMethod("BuildBlue"));
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Namespace_for_CarBuilder_has_method_BuildRed()
+    {
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        Assert.NotNull(carBuilderType?.GetMethod("BuildRed"));
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Namespace_for_CarBuilder_returns_Blue_Type()
+    {
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        var returnType = carBuilderType?.GetMethod("BuildBlue")?.ReturnType;
+        Assert.Equal("BlueRemoteControlCarTeam.RemoteControlCar", returnType?.FullName);
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Namespace_for_CarBuilder_returns_Red_Type()
+    {
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        var returnType = carBuilderType?.GetMethod("BuildRed")?.ReturnType;
+        Assert.Equal("RedRemoteControlCarTeam.RemoteControlCar", returnType?.FullName);
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Namespace_for_CarBuilder_can_BuildBlue_car()
+    {
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        var blueRemoteControlCar = carBuilderType?.GetMethod("BuildBlue")?.Invoke(null, null);
+        Assert.NotNull(blueRemoteControlCar);
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Namespace_for_CarBuilder_can_BuildRed_car()
+    {
+        var carBuilderType = Type.GetType("Combined.CarBuilder");
+        var redRemoteControlCar = carBuilderType?.GetMethod("BuildRed")?.Invoke(null, null);
+        Assert.NotNull(redRemoteControlCar);
     }
 }

From 7e66e90f7472769dbad86ac3713f2c62afb4a17e Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Tue, 17 Nov 2020 09:37:37 +0000
Subject: [PATCH 272/327] consolidate references to arithmetic-overflow and
 overflow

manual construction of about.md to avoid merge conflicts

* overflow remove references to arithmetic-overflow

* overflow renamed arithmetic-overflow in design.md
---
 concepts/arithmetic-overflow/about.md                  | 1 -
 concepts/arithmetic-overflow/links.json                | 1 -
 exercises/concept/instruments-of-texas/.meta/design.md | 2 +-
 3 files changed, 1 insertion(+), 3 deletions(-)
 delete mode 100644 concepts/arithmetic-overflow/about.md
 delete mode 100644 concepts/arithmetic-overflow/links.json

diff --git a/concepts/arithmetic-overflow/about.md b/concepts/arithmetic-overflow/about.md
deleted file mode 100644
index 866d543703..0000000000
--- a/concepts/arithmetic-overflow/about.md
+++ /dev/null
@@ -1 +0,0 @@
-TODO: add information on arithmetic-overflow concept
diff --git a/concepts/arithmetic-overflow/links.json b/concepts/arithmetic-overflow/links.json
deleted file mode 100644
index fe51488c70..0000000000
--- a/concepts/arithmetic-overflow/links.json
+++ /dev/null
@@ -1 +0,0 @@
-[]
diff --git a/exercises/concept/instruments-of-texas/.meta/design.md b/exercises/concept/instruments-of-texas/.meta/design.md
index 9397af9929..d3ea066947 100644
--- a/exercises/concept/instruments-of-texas/.meta/design.md
+++ b/exercises/concept/instruments-of-texas/.meta/design.md
@@ -23,5 +23,5 @@ This Concept Exercise's prerequisites Concepts are:
 - `inheritance`: inheriting from the `Exception` class for the custom exception.
 - `strings`: converting an into a string
 - `if-statements`: use of `&&`
-- `arithmetic-overflow`
+- `overflow`
 - `signed-integers`: `Int32.MaxValue`

From 4b5486cff94821ea439aaf667571a8573de8c336 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Wed, 18 Nov 2020 08:22:09 +0100
Subject: [PATCH 273/327] datetimes. Constructor for test culture en us

---
 .../booking-up-for-beauty/.meta/config.json   |  6 +++
 .../BookingUpForBeautyTests.cs                | 51 +++----------------
 2 files changed, 14 insertions(+), 43 deletions(-)

diff --git a/exercises/concept/booking-up-for-beauty/.meta/config.json b/exercises/concept/booking-up-for-beauty/.meta/config.json
index 80aa03f7fd..17c69a3217 100644
--- a/exercises/concept/booking-up-for-beauty/.meta/config.json
+++ b/exercises/concept/booking-up-for-beauty/.meta/config.json
@@ -1,4 +1,10 @@
 {
+  "contributors": [
+    {
+      "github_username": "valentin-p",
+      "exercism_username": "valentin-p"
+    }
+  ],
   "authors": [
     {
       "github_username": "ErikSchierboom",
diff --git a/exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs b/exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs
index d41d385a78..584bc3b71a 100644
--- a/exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs
+++ b/exercises/concept/booking-up-for-beauty/BookingUpForBeautyTests.cs
@@ -1,13 +1,17 @@
 using Xunit;
-using Xunit.Sdk;
 using System;
 using System.Globalization;
-using System.Reflection;
 using System.Threading;
 
-[UseCulture("en-US")]
 public class AppointmentTests
 {
+    public AppointmentTests()
+    {
+        var enUsCulture = new CultureInfo("en-US");
+        Thread.CurrentThread.CurrentCulture = enUsCulture;
+        Thread.CurrentThread.CurrentUICulture = enUsCulture;
+    }
+
     [Fact]
     public void Schedule_date_using_only_numbers()
     {
@@ -152,48 +156,9 @@ public void Description_on_wednesday_morning()
         Assert.Equal("You have an appointment on 9/9/2020 9:09:09 AM.", Appointment.Description(new DateTime(2020, 9, 9, 9, 9, 9)));
     }
 
-    [Fact]
+    [Fact(Skip = "Remove this Skip property to run this test")]
     public void Anniversary_date()
     {
         Assert.Equal(new DateTime(DateTime.Now.Year, 9, 15), Appointment.AnniversaryDate());
     }
-
-    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
-    private class UseCultureAttribute : BeforeAfterTestAttribute
-    {
-        private readonly CultureInfo _culture;
-        private readonly CultureInfo _uiCulture;
-        private CultureInfo _originalCulture;
-        private CultureInfo _originalUiCulture;
-
-        public UseCultureAttribute(string culture)
-            : this(culture, culture) { }
-
-        public UseCultureAttribute(string culture, string uiCulture)
-        {
-            _culture = new CultureInfo(culture, false);
-            _uiCulture = new CultureInfo(uiCulture, false);
-        }
-
-        public override void Before(MethodInfo methodUnderTest)
-        {
-            _originalCulture = Thread.CurrentThread.CurrentCulture;
-            _originalUiCulture = Thread.CurrentThread.CurrentUICulture;
-
-            Thread.CurrentThread.CurrentCulture = _culture;
-            Thread.CurrentThread.CurrentUICulture = _uiCulture;
-
-            CultureInfo.CurrentCulture.ClearCachedData();
-            CultureInfo.CurrentUICulture.ClearCachedData();
-        }
-
-        public override void After(MethodInfo methodUnderTest)
-        {
-            Thread.CurrentThread.CurrentCulture = _originalCulture;
-            Thread.CurrentThread.CurrentUICulture = _originalUiCulture;
-
-            CultureInfo.CurrentCulture.ClearCachedData();
-            CultureInfo.CurrentUICulture.ClearCachedData();
-        }
-    }
 }

From 159b5cd99423ccb37269c5cfd178a46601ac4b78 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Wed, 18 Nov 2020 15:33:06 +0100
Subject: [PATCH 274/327] keep only concept datetimes

---
 concepts/datetime/about.md   | 1 -
 concepts/datetime/links.json | 1 -
 2 files changed, 2 deletions(-)
 delete mode 100644 concepts/datetime/about.md
 delete mode 100644 concepts/datetime/links.json

diff --git a/concepts/datetime/about.md b/concepts/datetime/about.md
deleted file mode 100644
index 51b8d67912..0000000000
--- a/concepts/datetime/about.md
+++ /dev/null
@@ -1 +0,0 @@
-TODO: add information on datetime concept
diff --git a/concepts/datetime/links.json b/concepts/datetime/links.json
deleted file mode 100644
index fe51488c70..0000000000
--- a/concepts/datetime/links.json
+++ /dev/null
@@ -1 +0,0 @@
-[]

From 275f5587cfebf64865f7a622400cb9aa13320f33 Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Wed, 18 Nov 2020 18:39:04 +0000
Subject: [PATCH 275/327] rename exercise to developer-privileges

manual construction of about.md to avoid merge conflicts

* developer-privileges - renamed why-cant-i-push-to-main exercise
 to developer-privileges
---
 .../.docs/hints.md                                              | 0
 .../.docs/instructions.md                                       | 0
 .../.docs/introduction.md                                       | 0
 .../.meta/Example.cs                                            | 0
 .../.meta/config.json                                           | 0
 .../.meta/design.md                                             | 0
 .../WhyCantIPushToMain.cs                                       | 0
 .../WhyCantIPushToMain.csproj                                   | 0
 .../WhyCantIPushToMainTests.cs                                  | 0
 reference/exercises.json                                        | 2 +-
 10 files changed, 1 insertion(+), 1 deletion(-)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.docs/hints.md (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.docs/instructions.md (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.docs/introduction.md (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.meta/Example.cs (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.meta/config.json (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/.meta/design.md (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/WhyCantIPushToMain.cs (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/WhyCantIPushToMain.csproj (100%)
 rename exercises/concept/{why-cant-i-push-to-main => developer-privileges}/WhyCantIPushToMainTests.cs (100%)

diff --git a/exercises/concept/why-cant-i-push-to-main/.docs/hints.md b/exercises/concept/developer-privileges/.docs/hints.md
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.docs/hints.md
rename to exercises/concept/developer-privileges/.docs/hints.md
diff --git a/exercises/concept/why-cant-i-push-to-main/.docs/instructions.md b/exercises/concept/developer-privileges/.docs/instructions.md
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.docs/instructions.md
rename to exercises/concept/developer-privileges/.docs/instructions.md
diff --git a/exercises/concept/why-cant-i-push-to-main/.docs/introduction.md b/exercises/concept/developer-privileges/.docs/introduction.md
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.docs/introduction.md
rename to exercises/concept/developer-privileges/.docs/introduction.md
diff --git a/exercises/concept/why-cant-i-push-to-main/.meta/Example.cs b/exercises/concept/developer-privileges/.meta/Example.cs
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.meta/Example.cs
rename to exercises/concept/developer-privileges/.meta/Example.cs
diff --git a/exercises/concept/why-cant-i-push-to-main/.meta/config.json b/exercises/concept/developer-privileges/.meta/config.json
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.meta/config.json
rename to exercises/concept/developer-privileges/.meta/config.json
diff --git a/exercises/concept/why-cant-i-push-to-main/.meta/design.md b/exercises/concept/developer-privileges/.meta/design.md
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/.meta/design.md
rename to exercises/concept/developer-privileges/.meta/design.md
diff --git a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.cs b/exercises/concept/developer-privileges/WhyCantIPushToMain.cs
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.cs
rename to exercises/concept/developer-privileges/WhyCantIPushToMain.cs
diff --git a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj b/exercises/concept/developer-privileges/WhyCantIPushToMain.csproj
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMain.csproj
rename to exercises/concept/developer-privileges/WhyCantIPushToMain.csproj
diff --git a/exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMainTests.cs b/exercises/concept/developer-privileges/WhyCantIPushToMainTests.cs
similarity index 100%
rename from exercises/concept/why-cant-i-push-to-main/WhyCantIPushToMainTests.cs
rename to exercises/concept/developer-privileges/WhyCantIPushToMainTests.cs
diff --git a/reference/exercises.json b/reference/exercises.json
index 7274290011..0ee5966d28 100644
--- a/reference/exercises.json
+++ b/reference/exercises.json
@@ -790,7 +790,7 @@
       ]
     },
     {
-      "slug": "why-cant-i-push-to-main",
+      "slug": "developer-privileges",
       "level": "introductory",
       "completion-status": "complete",
       "document-link": "",

From dbac6423208f1901a8222b96121a7625f18663e4 Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Thu, 19 Nov 2020 12:51:34 +0000
Subject: [PATCH 276/327] classes concept - ensured related scraped concepts
 were included

manual construction of about.md to avoid merge conflicts

* elons-toys ensure inclusion of all scraped class concepts
are included in about.md for classes

* elons-toys added paras on visibility

* elons-toys updated exercises.json to include classes sub-concepts

* elons-toys update to wrong file - fixed

* elons-toys warn of variable name clashes
---
 concepts/classes/about.md | 17 ++++++++++++--
 reference/exercises.json  | 48 +++++----------------------------------
 2 files changed, 21 insertions(+), 44 deletions(-)

diff --git a/concepts/classes/about.md b/concepts/classes/about.md
index d254869203..858f591de7 100644
--- a/concepts/classes/about.md
+++ b/concepts/classes/about.md
@@ -7,7 +7,9 @@ Access to members can be restricted through access modifiers, the two most commo
 
 It is customary to specify an access modifier for all members. If no access modifier is specified, it will default to `private`.
 
-The above-mentioned grouping of related data and behavior plus restricting access to members is known as _encapsulation_, which is one of the core object-oriented concepts.
+The above-mentioned grouping of related data and behavior plus restricting access to members is known as [encapsulation][encapsulation], which is one of the core object-oriented concepts.
+
+The combination of field values of an object at any one time are known as the object's [state][object-state].
 
 You can think of a class as a template for creating instances of that class. To [create an instance of a class][creating-objects] (also known as an _object_), the [`new` keyword][new] is used:
 
@@ -21,7 +23,7 @@ var myCar = new Car();
 var yourCar = new Car();
 ```
 
-[Fields][fields] have a type and a name (defined in [camelCase][camel-case]) and can be defined anywhere in a class (defined in [PascalCase][pascal-case]).
+[Fields][fields] have a type and a name (defined, by convention, in [camelCase][camel-case]) and can be defined anywhere in a class (defined, again by convention, in [PascalCase][pascal-case]).
 
 ```csharp
 class Car
@@ -86,6 +88,12 @@ class CarImporter
 }
 ```
 
+The class and method structure provides a natural way to limit visibility of program elements such as fields and methods and avoid the well-known [problem of global state][so-global-state-problem]. Public fields, methods and other members have to be qualified with the object name, `object.field` or `object.method()`, (class name in the case of statics) to be seen by code outside the class. Variables and parameters declared within a method can be seen only within that method.
+
+One thing to be wary of with this approach is that if a field name and the name of a variable or parameter in a method are the same then the field name will be ignored by code within the method which may not be what you desire.  In general, you should avoid this where possible although it is a common pattern in constructors.  If it is appropriate for the field and variable name to be the same then qualify the field name with the `this` keyword within the method.
+
+These [access modifiers][access-modifiers] can be used to further limit visibility.
+
 [fields]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/fields
 [methods]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/methods
 [this]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/this
@@ -98,3 +106,8 @@ class CarImporter
 [default-values]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/default-values
 [camel-case]: https://techterms.com/definition/camelcase
 [pascal-case]: https://techterms.com/definition/pascalcase
+[encapsulation]: https://docs.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/architectural-principles#encapsulation
+[visibility]: https://docs.microsoft.com/en-us/cpp/c-language/scope-and-visibility?view=msvc-160
+[object-state]: https://cs.stackexchange.com/questions/6536/definition-of-the-state-of-an-object-in-oop
+[so-global-state-problem]: https://softwareengineering.stackexchange.com/questions/148108/why-is-global-state-so-evil
+[access-modifiers]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/access-modifiers
diff --git a/reference/exercises.json b/reference/exercises.json
index 0ee5966d28..13f0cfab64 100644
--- a/reference/exercises.json
+++ b/reference/exercises.json
@@ -24,63 +24,27 @@
             {
               "name": "- [Classes][classes]",
               "line-number": 11
-            }
-          ]
-        },
-        {
-          "name": "encapsulation",
-          "track-neutral-concept": "reference/concepts/encapsulation.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Encapsulation][encapsulation]",
               "line-number": 13
-            }
-          ]
-        },
-        {
-          "name": "fields",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "- Fields",
               "line-number": 14
-            }
-          ]
-        },
-        {
-          "name": "objects",
-          "track-neutral-concept": "reference/concepts/objects.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Objects][objects]",
               "line-number": 32
-            }
-          ]
-        },
-        {
-          "name": "state",
-          "track-neutral-concept": "reference/concepts/state.md",
-          "original-concepts": [
+            },
             {
               "name": "- [State][state]",
               "line-number": 36
-            }
-          ]
-        },
-        {
-          "name": "visibility",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "  - Visibility (\u0060public\u0060; \u0060private\u0060; etc.)",
               "line-number": 123
-            }
-          ]
-        },
-        {
-          "name": "default-value",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "  - Default values (a \u0060bool\u0060 being \u0060false\u0060 by default; etc.)",
               "line-number": 133

From bc9bdec2d67fc1cfbfddcf00a52cc82f341ddde5 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 19 Nov 2020 08:04:07 -0500
Subject: [PATCH 277/327] Update exercise-report document

Co-authored-by: github-actions[bot] 
---
 reference/exercise-errors.json | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json
index 6132a6a218..8fc0ff2267 100644
--- a/reference/exercise-errors.json
+++ b/reference/exercise-errors.json
@@ -4,6 +4,36 @@
       "Severity": "error",
       "Message": "Failed to find concept compound-assignment, from the attack-of-the-trolls design.md, in exercises.json file",
       "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept encapsulation, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept fields, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept objects, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept state, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept visibility, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "Failed to find concept default-value, from the elons-toys design.md, in exercises.json file",
+      "Source": "merge"
     }
   ]
 }

From 5ebd791b2c07dfba37ba59b179a037b6ff7d42bc Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Thu, 19 Nov 2020 13:40:04 +0000
Subject: [PATCH 278/327] elons-toys - removed concepts from design.md

manual construction of about.md to avoid merge conflicts

* exerise-errors fixed change to reference/exercises.json

sub-concepts associated with classes were removed from exercises.json without a corresponding change to _design.md_.  Fixed in this commit.
---
 exercises/concept/elons-toys/.meta/design.md | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/exercises/concept/elons-toys/.meta/design.md b/exercises/concept/elons-toys/.meta/design.md
index 197062e007..ff712986a7 100644
--- a/exercises/concept/elons-toys/.meta/design.md
+++ b/exercises/concept/elons-toys/.meta/design.md
@@ -24,12 +24,6 @@
 ## Concepts
 
 - `classes`: know what classes are; know what encapsulation is; know what fields are; know how to create an object; know how to update state through methods; know about the `void` type.
-- `encapsulation`: know how to encapsulate date; know what advantages encapsulation provides
-- `fields`: know the syntax and behavior of fields
-- `objects`: know what an object is; know how objects relate to classes
-- `state`: know how state is maintained within a class
-- `visibility`: know about private and public visibility; know the advantage of keeping visibility to a minimum
-- `default-value`: know that an uninitialized field has a default value
 
 ## Prerequisites
 

From 0f2d7d47482d97444571c39d186be501eff4d01e Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Thu, 19 Nov 2020 14:42:18 +0100
Subject: [PATCH 279/327] Update exercise-report document

Co-authored-by: github-actions[bot] 
---
 reference/exercise-errors.json | 30 ------------------------------
 1 file changed, 30 deletions(-)

diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json
index 8fc0ff2267..6132a6a218 100644
--- a/reference/exercise-errors.json
+++ b/reference/exercise-errors.json
@@ -4,36 +4,6 @@
       "Severity": "error",
       "Message": "Failed to find concept compound-assignment, from the attack-of-the-trolls design.md, in exercises.json file",
       "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept encapsulation, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept fields, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept objects, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept state, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept visibility, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
-    },
-    {
-      "Severity": "error",
-      "Message": "Failed to find concept default-value, from the elons-toys design.md, in exercises.json file",
-      "Source": "merge"
     }
   ]
 }

From 7459d901e20fa28159aea75a585f66f57c990da2 Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Fri, 20 Nov 2020 13:41:33 +0000
Subject: [PATCH 280/327] international-calling-connoisseur - reformat
 instructions.md.

manual construction of about.md to avoid merge conflicts

* international-dialing amend international-ca... instructions.md

Redo instructions.md to follow the same format as other exercises.

* Update languages/exercises/concept/international-calling-connoisseur/.docs/instructions.md

Co-authored-by: Erik Schierboom 

Co-authored-by: Erik Schierboom 
---
 .../.docs/instructions.md                     | 64 ++++++++-----------
 1 file changed, 27 insertions(+), 37 deletions(-)

diff --git a/exercises/concept/international-calling-connoisseur/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
index 143797402b..0f3707059f 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/instructions.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
@@ -2,13 +2,15 @@ In this exercise you'll be writing code to keep track of international dialling
 
 The dictionary uses an integer for its keys (the dialing code) and a string (country name) for its values.
 
-You have 11 tasks which involve DialingCodes.
+You have 9 tasks which involve the  `DialingCodes` static class.
 
 ### 1. Create a new dictionary
 
+Implement the (static) method `DialingCodes.GetEmptyDictionary()` that returns an empty dictionary.
+
 ```csharp
 DialingCodes.GetEmptyDictionary();
-// empty dictionary
+// => empty dictionary
 ```
 
 ### 2. Create a pre-populated dictionary
@@ -17,93 +19,81 @@ There exists a pre-populated dictionary which contains the following 3 dialing c
 
 ```csharp
 DialingCodes.GetExistingDictionary();
-// 1 => "United States of America", 55 => "Brazil", 91 => "India"
+// => 1 => "United States of America", 55 => "Brazil", 91 => "India"
 ```
 
 ### 3. Add a country to an empty dictionary
 
-Add "United Kingdom" with a dialing code of 44:
+Implement the (static) method `DialingCodes.AddCountryToEmptyDictionary()` that creates a dictionary and adds a dialing code and associated country name to it.
 
 ```csharp
 DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom");
-// 44 => "United Kingdom"
+// => 44 => "United Kingdom"
 ```
 
 ### 4. Add a country to an existing dictionary
 
-Add "United Kingdom" with a dialing code of 44 to the dictionary created in task 2:
+Implement the (static) method `DialingCodes.AddCountryToExistingDictionary()` that adds a dialing code and associated country name to a non-empty dictionary.
 
 ```csharp
 DialingCodes.AddCountryToExistingDictionary(DialingCodes.GetExistingDictionary(),
   44, "United Kingdom");
-// 1 => "United States of America", 44 => "United Kingdom", 55 => "Brazil", 91 => "India"
+// => 1 => "United States of America", 44 => "United Kingdom", 55 => "Brazil", 91 => "India"
 ```
 
-### 5. Get the country name matching a country code
+### 5. Get the country name matching a dialing code
 
-Check that a country with the country name for dialing code 55
+Implement the (static) method `DialingCodes.GetCountryNameFromDictionary()` that takes a dialing code and returns the corresponding country name. If the dialing code is not contained in the dictionary then an empty string is returned.
 
 ```csharp
 DialingCodes.GetCountryNameFromDictionary(
   DialingCodes.GetExistingDictionary(), 55);
-// "Brazil"
+// => "Brazil"
+
+DialingCodes.GetCountryNameFromDictionary(
+  DialingCodes.GetExistingDictionary(), 999);
+// => string.Empty
 ```
 
 ### 6. Check that a country exists in the dictionary
 
-Check that a record for Brazil exists in the dictionary created in task 2
+Implement the (static) method `DialingCodes.CheckCodeExists()` to check whether a dialing code exists in the dictionary.
 
 ```csharp
 DialingCodes.CheckCodeExists(DialingCodes.GetExistingDictionary(), 55);
-// true
-```
-
-### 7. Attempt to get country name for a non-existent country code
-
-Request the country name for a code that is not in the existing dictionary, e.g. 999. An empty string should be returned:
-
-```csharp
-DialingCodes.GetCountryNameFromDictionary(
-  DialingCodes.GetExistingDictionary(), 999);
-// string.Empty
+// => true
 ```
 
-### 8. Update a country name
+### 7. Update a country name
 
-Change the name of "United States of America" to "Les États-Unis":
+Implement the (static) method `DialingCodes.UpdateDictionary()` which takes a dialing code and replaces the corresponding country name in the dictionary with the country name passed as a parameter. If the dialing code does not exist in the dictionary then the dictionary remains unchanged.
 
 ```csharp
 DialingCodes.UpdateDictionary(
   DialingCodes.GetExistingDictionary(), 1, "Les États-Unis");
-// 1 => "Les États-Unis", 55 => "Brazil", 91 => "India"
-```
-
-### 9. Attempt to update name of country that is not in the dictionary
+// => 1 => "Les États-Unis", 55 => "Brazil", 91 => "India"
 
-Try to change the name of a country with a code that is not in the dictionary e.g. 999. This should result in no change to the dictionary:
-
-```csharp
 DialingCodes.UpdateDictionary(
   DialingCodes.GetExistingDictionary(), 999, "Newlands");
 // 1 => "United States of America", 55 => "Brazil", 91 => "India"
 ```
 
-### 10. Remove a country from the dictionary
+### 8. Remove a country from the dictionary
 
-Remove India from the dictionary:
+Implement the (static) method `DialingCodes.RemoveCountryFromDictionary()` that takes a dialing code and will remove the corresponding record, dialing code + country name, from the dictionary.
 
 ```csharp
 DialingCodes.RemoveCountryFromDictionary(
   DialingCodes.GetExistingDictionary(), 91);
-// 1 => "United States of America", 55 => "Brazil"
+// => 1 => "United States of America", 55 => "Brazil"
 ```
 
-### 11. Find the country with the longest name
+### 9. Find the country with the longest name
 
-Process the values in the dictionary to find the one with the longest name:
+Implement the (static) method `DialingCodes.FindLongestCountryName()` which will return the name of the country with the longest name stored in the dictionary.
 
 ```csharp
 DialingCodes.FindLongestCountryName(
   DialingCodes.GetExistingDictionary());
-// "United States of America"
+// => "United States of America"
 ```

From 2aca1362cc9d80ecf0d56ad0f75f3fbfc7c5bc39 Mon Sep 17 00:00:00 2001
From: Sascha Mann 
Date: Tue, 24 Nov 2020 19:26:45 +0100
Subject: [PATCH 281/327] Format code

---
 concepts/classes/about.md                                       | 2 +-
 .../international-calling-connoisseur/.docs/instructions.md     | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/concepts/classes/about.md b/concepts/classes/about.md
index 858f591de7..a5b951d5db 100644
--- a/concepts/classes/about.md
+++ b/concepts/classes/about.md
@@ -90,7 +90,7 @@ class CarImporter
 
 The class and method structure provides a natural way to limit visibility of program elements such as fields and methods and avoid the well-known [problem of global state][so-global-state-problem]. Public fields, methods and other members have to be qualified with the object name, `object.field` or `object.method()`, (class name in the case of statics) to be seen by code outside the class. Variables and parameters declared within a method can be seen only within that method.
 
-One thing to be wary of with this approach is that if a field name and the name of a variable or parameter in a method are the same then the field name will be ignored by code within the method which may not be what you desire.  In general, you should avoid this where possible although it is a common pattern in constructors.  If it is appropriate for the field and variable name to be the same then qualify the field name with the `this` keyword within the method.
+One thing to be wary of with this approach is that if a field name and the name of a variable or parameter in a method are the same then the field name will be ignored by code within the method which may not be what you desire. In general, you should avoid this where possible although it is a common pattern in constructors. If it is appropriate for the field and variable name to be the same then qualify the field name with the `this` keyword within the method.
 
 These [access modifiers][access-modifiers] can be used to further limit visibility.
 
diff --git a/exercises/concept/international-calling-connoisseur/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
index 0f3707059f..dbbb1347ce 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/instructions.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
@@ -2,7 +2,7 @@ In this exercise you'll be writing code to keep track of international dialling
 
 The dictionary uses an integer for its keys (the dialing code) and a string (country name) for its values.
 
-You have 9 tasks which involve the  `DialingCodes` static class.
+You have 9 tasks which involve the `DialingCodes` static class.
 
 ### 1. Create a new dictionary
 

From 2470fa0f8d355483bca50be057cbdd06db488d93 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Fri, 4 Dec 2020 21:58:56 +0100
Subject: [PATCH 282/327] attack trolls. flag enums and attributes

* attack trolls. flag enums and attributes
---
 concepts/attributes/about.md                  | 29 ++++++++++++++-
 concepts/attributes/links.json                | 15 +++++++-
 concepts/bit-manipulation/about.md            |  3 +-
 concepts/compound-assignment/about.md         |  3 +-
 concepts/flag-enums/about.md                  |  3 +-
 concepts/flag-enums/links.json                | 20 ++++-------
 .../attack-of-the-trolls/.docs/hints.md       |  5 +++
 .../.docs/instructions.md                     | 10 +++---
 .../.docs/introduction.md                     | 35 +++++++++----------
 .../attack-of-the-trolls/.meta/config.json    |  6 ++++
 .../attack-of-the-trolls/.meta/design.md      |  8 ++---
 .../AttackOfTheTrollsTests.cs                 | 18 ++++++++++
 12 files changed, 107 insertions(+), 48 deletions(-)

diff --git a/concepts/attributes/about.md b/concepts/attributes/about.md
index 221347763c..d9b8a4f4f9 100644
--- a/concepts/attributes/about.md
+++ b/concepts/attributes/about.md
@@ -1 +1,28 @@
-TODO: add information on attributes concept
+A [C# `Attribute`][attribute-concept] provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported][attribute-targets] declarations.
+
+You can apply [an attribute][attribute] to a declaration by adding it between brackets `[]` before the declaration, the following example uses both a `ClassAttribute` and a `FieldAttribute`:
+
+```csharp
+[Class]
+public class MyClass
+{
+    [Field] public int myField;
+}
+```
+
+The declarative metadata only associates additional structured information to the code and does not modify its behavior, but that metadata is used by other part of the code to change how its target would behave or add, change or remove, restrict some its functionalities.
+
+Multiple predefined attributes exist like: `Flags`, `Obsolete`, `Conditional`. Note that the full name of the [`Flags` attribute][flags-attribute] is `FlagsAttribute`, but "Attribute" suffix can be omitted when using in the attribute.
+
+The following four predefined attributes are used regularly:
+
+- `[Flags]`: Predefined in the System namespace. Indicates the enum supports both bitwise operations and the method `Enum.HasFlag()`, additionally `ToString` would display all the flags: [see example][flags-example].
+- `[Obsolete]`: Predefined in the System namespace. Allows to add a message about why the code is obsolete, it can be used to display compiler warnings or errors.
+- `[Conditional]`: Predefined in the System.Diagnostics namespace. Allows to remove some method calls at compile time for debugging (diagnostics) purposes.
+- `[CallerMemberName]`: Predefined in the System.Runtime.CompilerServices namespace. Allows a method to obtain information about its caller.
+
+[attribute-concept]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/
+[attribute]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/attributes
+[attribute-targets]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets
+[flags-attribute]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0
+[flags-example]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0#examples
diff --git a/concepts/attributes/links.json b/concepts/attributes/links.json
index fe51488c70..a9be26ec21 100644
--- a/concepts/attributes/links.json
+++ b/concepts/attributes/links.json
@@ -1 +1,14 @@
-[]
+[
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/",
+    "description": "Attribute"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/attributes",
+    "description": "Tutorial"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/global",
+    "description": "Assembly level attributes"
+  }
+]
diff --git a/concepts/bit-manipulation/about.md b/concepts/bit-manipulation/about.md
index 44af0b9bbc..c3e5499a9b 100644
--- a/concepts/bit-manipulation/about.md
+++ b/concepts/bit-manipulation/about.md
@@ -1,4 +1,5 @@
-TODO: we need to reconsider the text below now that it is a stand alone concept or maybe bitwise manipulation should be introduced in a separate exercise and the flag-enums exercise and concept should take that as a dependency showing how bitwise manipulation is used in the context of enums.
+TODO: See #2112. We need to reconsider the text below now that it is a stand alone concept or maybe bitwise manipulation should be introduced in a separate exercise and the flag-enums exercise and concept should take that as a dependency showing how bitwise manipulation is used in the context of enums.
+
 To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags.
 
 ```csharp
diff --git a/concepts/compound-assignment/about.md b/concepts/compound-assignment/about.md
index 509b50ea59..ab4272662a 100644
--- a/concepts/compound-assignment/about.md
+++ b/concepts/compound-assignment/about.md
@@ -1,4 +1,5 @@
-TODO: I think we need a different exercise to introduce compound assignments (one that shows it being used in a more conventional numeric or string context. flag-enums could then take that as a dependency and show how it is used in this more unusual context.
+TODO: See issue #2112. I think we need a different exercise to introduce compound assignments (one that shows it being used in a more conventional numeric or string context. flag-enums could then take that as a dependency and show how it is used in this more unusual context.
+
 The bitwise operators can also be used as [compound assignments][compound-assignment], which are a shorthand notation where `x = op y` can be written as `x op= y`:
 
 ```csharp
diff --git a/concepts/flag-enums/about.md b/concepts/flag-enums/about.md
index 0e597e9c3f..b92279bc84 100644
--- a/concepts/flag-enums/about.md
+++ b/concepts/flag-enums/about.md
@@ -71,9 +71,8 @@ enum PhoneFeatures : byte
 ```
 
 [docs.microsoft.com-enumeration-types-as-bit-flags]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags
-[alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
 [or-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator-
 [and-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator-
 [bitwise-complement-operator]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator-
 [binary-literals]: https://riptutorial.com/csharp/example/6327/binary-literals
-[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1
+[has-flag]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=net-5.0
diff --git a/concepts/flag-enums/links.json b/concepts/flag-enums/links.json
index 8481c07e09..c752cb4467 100644
--- a/concepts/flag-enums/links.json
+++ b/concepts/flag-enums/links.json
@@ -1,30 +1,22 @@
 [
   {
     "url": "https://riptutorial.com/csharp/example/6327/binary-literals",
-    "description": "binary-literals"
+    "description": "Binary literals"
   },
   {
     "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-or-operator-",
-    "description": "or-operator"
+    "description": "Bitwise and shift operators"
   },
   {
-    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#logical-and-operator-",
-    "description": "and-operator"
-  },
-  {
-    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators#bitwise-complement-operator-",
-    "description": "bitwise-complement-operator"
-  },
-  {
-    "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=netcore-3.1",
-    "description": "has-flag"
+    "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum.hasflag?view=net-5.0",
+    "description": "Enum.HasFlag method"
   },
   {
     "url": "https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#enumeration-types-as-bit-flags",
-    "description": "docs.microsoft.com-enumeration-types-as-bit-flags"
+    "description": "Enums as bit flags"
   },
   {
     "url": "https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/",
-    "description": "alanzucconi.com-enum-flags-and-bitwise-operators"
+    "description": "alanzucconi.com bitwise operators"
   }
 ]
diff --git a/exercises/concept/attack-of-the-trolls/.docs/hints.md b/exercises/concept/attack-of-the-trolls/.docs/hints.md
index 3f57c30815..e63519bf80 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/hints.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/hints.md
@@ -1,5 +1,9 @@
 ## 1. Get default permissions for an account type
 
+- Define the `Permission` enum with values for the following permission types: `None`, `Read`, `Write` and `Delete`.
+- Using the enum flags would allow to use bitwise operations out of the box for the `Permission` enum, [see `enum` `Flags`][docs-enum-flags].
+- The `All` enum member can be defined as a combination of the `Read`, `Write` and `Delete` enum members.
+- Define the `AccountType` enum with values for the following account types: `Guest`, `User` and `Moderator`.
 - To handle each account type, one could use an `if` statement, but the [`switch` statement][docs.microsoft.com-switch-keyword] is a great alternative.
 - Combining flags means setting a specific bit to `1` using one of the [bitwise operators][docs.microsoft.com-bitwise-and-shift-operators].
 
@@ -17,3 +21,4 @@
 
 [docs.microsoft.com-bitwise-and-shift-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators
 [docs.microsoft.com-switch-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch
+[docs-enum-flags]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0
diff --git a/exercises/concept/attack-of-the-trolls/.docs/instructions.md b/exercises/concept/attack-of-the-trolls/.docs/instructions.md
index 8dea940d13..2cc5ede74f 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/instructions.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/instructions.md
@@ -8,15 +8,15 @@ There are three types of accounts, each with different default permissions:
 
 - Guests: can read posts.
 - Users: can read and write posts.
-- Moderators: can read, write and delete posts.
+- Moderators: can read, write and delete posts, they have all the permissions.
 
-Sometimes individual permissions are modified, for example giving a guest account the permission to also write posts.
-
-You have four tasks.
+Sometimes individual permissions can be modified, it is possible for example to give a guest account the permission to also write posts or revoking all permissions from an account would result in having none of the permissions.
 
 ## 1. Get default permissions for an account type
 
-First, define an `AccountType` enum to represent the three account types. Next, define a `Permission` enum to represent the three permission types and two extra ones: one for having no permissions at all, and for having all permissions.
+First, define an `AccountType` enum to represent the three account types: `Guest`, `User` and `Moderator`.
+
+Next, define a `Permission` enum to represent the three permission types: `Read`, `Write`, `Delete`, and two extra ones: `All` for having all permissions and `None` for having none of the permissions.
 
 Then implement the (_static_) `Permissions.Default()` method to return the default permissions for a specific account type:
 
diff --git a/exercises/concept/attack-of-the-trolls/.docs/introduction.md b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
index 4e9117a815..01ae714731 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/introduction.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
@@ -1,26 +1,29 @@
-## bit-manipulation
+## attributes
 
-To work with bits, C# supports the following operators:
+A [C# `Attribute`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/) provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) declarations.
 
-- `~`: bitwise complement
-- `<<`: left shift
-- `>>`: right shift
-- `&`: logical AND
-- `|`: logical OR
-- `^`: logical XOR
-
-Here is an example how to use a bitwise operator:
+You can apply an attribute by adding it on the line before the declaration using a `ClassAttribute` and a `FieldAttribute`:
 
 ```csharp
-1 << 2
-// => 4
+[Class]
+class MyClass
+{
+    [Field]
+    int myField;
+}
 ```
 
+This declarative metadata only associates additional structured information to the code and does not modify its behavior, but that metadata is used by other part of the code to change how its target would behave or add, change or remove, restrict some its functionalities.
+
+There is many [predefined and reserved attributes](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#conditional-attribute), for example: `Flags`, `Obsolete`, `Conditional`, each has a specific that can be looked up on the C# documentation. Note that the full name of an attribute like [`Flags`](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0) is `FlagsAttribute` by convention, but the suffix _Attribute_ can be omitted when applied on a declaration.
+
 ## flag-enums
 
-The C# `enum` type represents a fixed set of named constants (an enumeration). Normally, one can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the `Flags` attribute. A _flags_ enum's constants are interpreted as bitwise _flags_.
+The C# [`enum` type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) represents a fixed set of named constants (an enumeration).
+
+Normally, one `enum` member can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the [`Flags` attribute](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0). A _flags_ enum's constants are interpreted as bitwise _flags_ and therefor indicates the enum supports the bitwise operators and additional features like the method `Enum.HasFlag()`.
 
-A flags enum can be defined as follows (using binary integer notation):
+A flags enum can be defined as follows (using binary integer notation `0b`):
 
 ```csharp
 [Flags]
@@ -43,7 +46,3 @@ enum PhoneFeatures : byte
     Text = 0b00000010
 }
 ```
-
-## compound-assignment
-
-TODO: consider what to put here - do this in conjunction with issue #2529 cleanup about.md files and approach detailed in csharp/concepts/bit-manipulation/about.md.
diff --git a/exercises/concept/attack-of-the-trolls/.meta/config.json b/exercises/concept/attack-of-the-trolls/.meta/config.json
index 0c0ed1f186..5319467747 100644
--- a/exercises/concept/attack-of-the-trolls/.meta/config.json
+++ b/exercises/concept/attack-of-the-trolls/.meta/config.json
@@ -1,4 +1,10 @@
 {
+  "contributors": [
+    {
+      "github_username": "valentin-p",
+      "exercism_username": "valentin-p"
+    }
+  ],
   "authors": [
     {
       "github_username": "ErikSchierboom",
diff --git a/exercises/concept/attack-of-the-trolls/.meta/design.md b/exercises/concept/attack-of-the-trolls/.meta/design.md
index 82c6244cb1..1e1cf03db2 100644
--- a/exercises/concept/attack-of-the-trolls/.meta/design.md
+++ b/exercises/concept/attack-of-the-trolls/.meta/design.md
@@ -15,15 +15,14 @@ As this is an advanced exercise, there are no enum-related things that we should
 ## Concepts
 
 - `flag-enums`: know how to define a "flags" enum; know how to add, remove or check for flags; know how to change the underlying type of an enum.
-- `bit-manipulation`: know how to use bitwise operators to manipulate bits.
-- `compound-assignment`: know how to use compound assignments )`&=`, etc)
+- `attributes`: know how to annotate the enum with the `[Flags]` attribute.
 
 ## Prerequisites
 
 This exercise's prerequisites Concepts are:
 
 - `enums`: know how to define the `enum`.
-- `attributes`: know how to annotate the enum with the `[Flags]` attribute.
+- `bit-manipulation`: know how to use bitwise operators to manipulate bits.
 - `integers`: know of other integer types than `int` and know about binary integer literals.
 
 ## Representer
@@ -34,7 +33,6 @@ This exercise does not require any specific representation logic to be added to
 
 This exercise could benefit from having an [analyzer][analyzer] that can comment on:
 
-- Verify that the `Permission` enum is marked with the `[Flags]` attribute.
 - Suggest using `byte` as the enum's backing type if no backing type was explicitly specified.
 
 [analyzer]: https://github.com/exercism/csharp-analyzer
@@ -43,6 +41,6 @@ This exercise could benefit from having an [analyzer][analyzer] that can comment
 [docs.microsoft.com-bitwise-and-shift-operators]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators
 [docs.microsoft.com-switch-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch
 [docs.microsoft.com-binary-notation]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#integer-literals
-[docs.microsoft.com-flagsattribute]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=netcore-3.1
+[docs.microsoft.com-flagsattribute]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0
 [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
 [concept-bitwise-manipulation]: ../../../../../reference/concepts/bitwise_manipulation.md
diff --git a/exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs b/exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs
index 3646faba13..e2121ca4d4 100644
--- a/exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs
+++ b/exercises/concept/attack-of-the-trolls/AttackOfTheTrollsTests.cs
@@ -3,6 +3,24 @@
 public class PermissionsTests
 {
     [Fact]
+    public void Permissions_read_write_can_be_combined_as_flags()
+    {
+        Assert.Equal("Read, Write", (Permission.Read | Permission.Write).ToString());
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Combining_none_delete_permissions_is_same_as_delete_permission()
+    {
+        Assert.Equal("Delete", (Permission.Delete | Permission.None).ToString());
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
+    public void Combining_read_write_delete_permissions_is_same_as_all_permission()
+    {
+        Assert.Equal("All", (Permission.Read | Permission.Write | Permission.Delete).ToString());
+    }
+
+    [Fact(Skip = "Remove this Skip property to run this test")]
     public void Default_for_guest()
     {
         Assert.Equal(Permission.Read, Permissions.Default(AccountType.Guest));

From c24a0b0a753e46baeaa4ca628f0c867ddb777afe Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
 <41898282+github-actions[bot]@users.noreply.github.com>
Date: Sun, 6 Dec 2020 15:06:57 +0100
Subject: [PATCH 283/327] Update exercise-report document

Co-authored-by: github-actions[bot] 
---
 reference/exercise-errors.json | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/reference/exercise-errors.json b/reference/exercise-errors.json
index 6132a6a218..6aca34b701 100644
--- a/reference/exercise-errors.json
+++ b/reference/exercise-errors.json
@@ -2,8 +2,13 @@
   "Errors": [
     {
       "Severity": "error",
-      "Message": "Failed to find concept compound-assignment, from the attack-of-the-trolls design.md, in exercises.json file",
+      "Message": "Failed to find concept attributes, from the attack-of-the-trolls design.md, in exercises.json file",
       "Source": "merge"
+    },
+    {
+      "Severity": "error",
+      "Message": "The bit-manipulation concept has no learning objectives on the exercise report - update the design.md for the attack-of-the-trolls exercise",
+      "Source": "missingLearningObjective"
     }
   ]
 }

From 33039c531f914553c8b94e80d31cb2cfc0ce3040 Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Thu, 10 Dec 2020 09:21:25 +0000
Subject: [PATCH 284/327] polymorphism concept

* polymorphism changed text to include polymorphism concept as part of the inheritance concept.

* polymorphism changed config to include polymorphism concept as part of the inheritance concept.

* polymorphism fixed omissions

* polymorphism fixed omissions

* Apply suggestions from code review

Co-authored-by: Erik Schierboom 

Co-authored-by: Erik Schierboom 
---
 concepts/inheritance/about.md                 | 45 +++++++++++++++++++
 .../.docs/introduction.md                     | 41 +++++++++++++++++
 .../wizards-and-warriors/.meta/design.md      |  1 -
 reference/exercises.json                      |  8 +---
 4 files changed, 87 insertions(+), 8 deletions(-)

diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md
index 7ba8e9ef9c..74e8393691 100644
--- a/concepts/inheritance/about.md
+++ b/concepts/inheritance/about.md
@@ -61,9 +61,52 @@ class Car : Vehicle
 }
 ```
 
+Where more than one class is derived from a base class the two (or more) sub-classes will often implement different versions of a base class method. This is a very important principle called [polymorphism][polymorphism]. For instance in a variation on the above example we show how code using `Vehicle` can change its behavior depending on what type of vehicle has been instantiated.
+
+```csharp
+abstract class Vehicle
+{
+   public abstract string GetDescription();
+}
+
+class Car : Vehicle
+{
+   public Car()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Runabout";
+   }
+}
+
+class Rig : Vehicle
+{
+   public Rig()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Big Rig";
+   }
+}
+
+Vehicle v1 = new Car();
+Vehicle v2 = new Rig();
+
+v1.GetDescription();
+// => Runabout
+v2.GetDescription();
+// => Big Rig
+```
+
 To prevent a class being inherited, add the [`sealed` modifier][sealed-classes].
 Some practitioners try to avoid inheriting from concrete classes (as discussed in [this SO question][pro-sealed]) and the _sealed_ modifier supports this approach. On the other hand many C# developers consider them a hindrance to maintenance as discussed in some of the comments on [this question][anti-sealed]. The advice is to use the sealed modifier sparingly until you have gained confidence in their use for your requirements.
 
+The following [article][new-vs-override] describes `new` as an alternative to the `override` modifier. This is occasionally useful, perhaps with convoluted class hierarchies and/or some sort of clash of libraries.
+
 [abstract-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/abstract
 [virtual-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/virtual
 [override-keyword]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/override
@@ -76,3 +119,5 @@ Some practitioners try to avoid inheriting from concrete classes (as discussed i
 [sealed-classes]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/abstract-and-sealed-classes-and-class-members#sealed-classes-and-class-members
 [pro-sealed]: https://stackoverflow.com/questions/16724946/why-derive-from-a-concrete-class-is-a-poor-design
 [anti-sealed]: https://stackoverflow.com/questions/7777611/when-and-why-would-you-seal-a-class
+[new-vs-override]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/knowing-when-to-use-override-and-new-keywords
+[polymorphism]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/polymorphism
diff --git a/exercises/concept/wizards-and-warriors/.docs/introduction.md b/exercises/concept/wizards-and-warriors/.docs/introduction.md
index 26997c506f..6976e1bc54 100644
--- a/exercises/concept/wizards-and-warriors/.docs/introduction.md
+++ b/exercises/concept/wizards-and-warriors/.docs/introduction.md
@@ -61,3 +61,44 @@ class Car : Vehicle
     }
 }
 ```
+
+Where more than one class is derived from a base class the two (or more) classes will often implement different versions of a base class method. This is a very important principle called polymorphism. For instance in a variation on the above example we show how code using `Vehicle` can change its behavior depending on what type of vehicle has been instantiated.
+
+```csharp
+abstract class Vehicle
+{
+   public abstract string GetDescription();
+}
+
+class Car : Vehicle
+{
+   public Car()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Runabout";
+   }
+}
+
+class Rig : Vehicle
+{
+   public Rig()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Big Rig";
+   }
+}
+
+Vehicle v1 = new Car();
+Vehicle v2 = new Rig();
+
+v1.GetDescription();
+// => Runabout
+v2.GetDescription();
+// => Big Rig
+```
diff --git a/exercises/concept/wizards-and-warriors/.meta/design.md b/exercises/concept/wizards-and-warriors/.meta/design.md
index 822a3489f6..02935724e6 100644
--- a/exercises/concept/wizards-and-warriors/.meta/design.md
+++ b/exercises/concept/wizards-and-warriors/.meta/design.md
@@ -15,7 +15,6 @@
 ## Concepts
 
 - `inheritance`: know what inheritance is; know how to inherit from a class; know that all types inherit from `object`; know what abstract and sealed classes are; know what abstract and virtual methods are; know how to override methods; know about the `protected` visibility modifier.
-- `polymorphism`: know the syntax rules of virtual methods; understand the power of polymorphism
 
 ## Prerequisites
 
diff --git a/reference/exercises.json b/reference/exercises.json
index 13f0cfab64..d456db1a42 100644
--- a/reference/exercises.json
+++ b/reference/exercises.json
@@ -66,13 +66,7 @@
             {
               "name": " [Inheritance][inheritance]",
               "line-number": 16
-            }
-          ]
-        },
-        {
-          "name": "polymorphism",
-          "track-neutral-concept": "reference/concepts/polymorphism.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Polymorphism][polymorphism]",
               "line-number": 34

From 719466f088270723bba6f49b104f2ffcba5ce081 Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Fri, 11 Dec 2020 10:44:56 +0100
Subject: [PATCH 285/327] enums concept about.md

* enums concept adding enum parse string in the about.md, couple of other fixes.
---
 concepts/enums/about.md                       | 66 ++++++++++++++++---
 concepts/enums/links.json                     | 15 ++++-
 .../concept/logs-logs-logs/.docs/hints.md     | 12 ++--
 .../logs-logs-logs/.docs/instructions.md      |  2 +-
 .../concept/logs-logs-logs/.meta/config.json  |  6 ++
 5 files changed, 86 insertions(+), 15 deletions(-)

diff --git a/concepts/enums/about.md b/concepts/enums/about.md
index fa2e10dc8a..c0e8fcda83 100644
--- a/concepts/enums/about.md
+++ b/concepts/enums/about.md
@@ -1,14 +1,14 @@
-You can use an enum whenever you have a fixed set of constant values. Using an enum gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`).
+You can use [Enumeration types][enumeration types] whenever you have a fixed set of constant values. Using an `enum` gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`).
 
-Each enum member has an associated integer value associated with it. If no value is explicitly defined for an enum member, its value is automatically assigned to `1` plus + the previous member's value. If the first member does not have an explicit value, its value is set to `0`.
+Each enum member is an association of a name and an `int` value. If the first member does not have an explicit value, its value is set to `0`. If no value is explicitly defined for an enum member, its value is automatically assigned to the previous member's value plus `1`.
 
 ```csharp
 enum Season
 {
-    Spring,     // Value is 0
-    Summer = 2, // Value is 2
-    Autumn,     // Value is 3
-    Winter = 7  // Value is 7
+    Spring,     // Auto set 0
+    Summer = 2, // Set the value 2
+    Autumn,     // Auto set 3
+    Winter = 7  // Set the value 7
 }
 ```
 
@@ -19,11 +19,26 @@ Users.WithStatus(1)
 Users.WithStatus(Status.Active)
 ```
 
-For someone reading the code, the second (enum) version will be easier to comprehend.
+For someone reading the code, the second version (with enum) will be easier to comprehend.
 
-You should always consider using an enum whenever you want to model something as a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof.
+## Numeric type Enums
 
-Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to any enum value:
+While the default numeric type of the values is `int`, it can be changed by explicitly specifying any other [integral numeric][integral numeric] type.
+
+The following enum use the `byte` numeric type for its values:
+
+```csharp
+enum Priority : byte
+{
+    Low = 0,
+    Medium = 127,
+    High = 255
+}
+```
+
+## Convert to an Enum member
+
+You should always consider using an enum whenever you want to model something like a boolean. Besides the aforementioned readability benefits, enums have another advantage over booleans: new values can always be added to an enum, whereas a boolean value will only ever be `true` or `false`. Using an enum is thus more future proof.
 
 ```csharp
 enum Status
@@ -32,7 +47,40 @@ enum Status
     Active = 1
 }
 
+Status active = (Status) 1;
+active == Status.Active; // True
+```
+
+Note that while one _can_ cast integer values to an enum, doing so can lead to unexpected results when the integer value doesn't map to some enum value:
+
+```csharp
 Status status = (Status) 2;
 status == Status.Inactive; // False
 status == Status.Active;   // False
 ```
+
+## Parsing an enum
+
+It's sometimes useful to convert a string to an enum member based on its name with [`Enum.Parse`][enum parse]:
+
+```csharp
+var input = "Inactive";
+Status status = (Status)Enum.Parse(typeof(Status), input);
+// Inactive
+```
+
+To check if a name or a value exists in the enum, you can use [`Enum.TryParse`][enum tryparse] or [`Enum.IsDefined`][enum isdefined], both return a boolean indicating if the enum member exists:
+
+```csharp
+bool doesExist = Enum.IsDefined(typeof(Status), "Inexistent");
+// False
+```
+
+More examples and best practices are available [here][enum examples].
+
+[enumeration types]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum
+[integral numeric]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types
+[enum parse]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.parse?view=net-5.0
+[enum tryparse]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=net-5.0
+[enum isdefined]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.isdefined?view=net-5.0
+[enum examples]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=net-5.0#examples
diff --git a/concepts/enums/links.json b/concepts/enums/links.json
index fe51488c70..d986dd8e86 100644
--- a/concepts/enums/links.json
+++ b/concepts/enums/links.json
@@ -1 +1,14 @@
-[]
+[
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum",
+    "description": "Enumeration types"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum.parse?view=net-5.0",
+    "description": "Parsing enums"
+  },
+  {
+    "url": "https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=net-5.0#examples",
+    "description": "Enum examples"
+  }
+]
diff --git a/exercises/concept/logs-logs-logs/.docs/hints.md b/exercises/concept/logs-logs-logs/.docs/hints.md
index 0af01c46ec..314a70478c 100644
--- a/exercises/concept/logs-logs-logs/.docs/hints.md
+++ b/exercises/concept/logs-logs-logs/.docs/hints.md
@@ -4,12 +4,12 @@
 
 ## 1. Parse log level
 
-- There is a [method to get a part of a string](https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=netcore-3.1).
-- You can use a [`switch` statement](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch) to elegantly handle the various log levels.
+- There is a [method to get a part of a string][docs.microsoft.com_system_string_substring].
+- You can use a [`switch` statement][docs.microsoft.com_keyword_switch] to elegantly handle the various log levels.
 
 ## 2. Support unknown log level
 
-- There is a [special switch case](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case) that can be used to catch unspecified cases.
+- There is a [special switch case][docs.microsoft.com_keyword_switch_default] that can be used to catch unspecified cases.
 
 ## 3. Convert log line to short format
 
@@ -17,5 +17,9 @@
 - Converting an enum to a number can be done through [casting][docs.microsoft.com_enumeration-types-casting] or by using a [format string][docs.microsoft.com_system.enum.tostring].
 
 [docs.microsoft.com-enumeration-types]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types
+[docs.microsoft.com_system_string_substring]: https://docs.microsoft.com/en-us/dotnet/api/system.string.substring?view=net-5.0
+[docs.microsoft.com_keyword_switch]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch
+[docs.microsoft.com_keyword_switch_default]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/switch#the-default-case
 [docs.microsoft.com_enumeration-types-casting]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/enumeration-types#code-try-1
-[docs.microsoft.com_creating-an-enumeration-type]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=netcore-3.0#creating-an-enumeration-type
+[docs.microsoft.com_creating-an-enumeration-type]: https://docs.microsoft.com/en-us/dotnet/api/system.enum?view=net-5.0#creating-an-enumeration-type
+[docs.microsoft.com_system.enum.tostring]: https://docs.microsoft.com/en-us/dotnet/api/system.enum.tostring?view=net-5.0
diff --git a/exercises/concept/logs-logs-logs/.docs/instructions.md b/exercises/concept/logs-logs-logs/.docs/instructions.md
index 9e26f8508e..4ca2a0a0a5 100644
--- a/exercises/concept/logs-logs-logs/.docs/instructions.md
+++ b/exercises/concept/logs-logs-logs/.docs/instructions.md
@@ -44,7 +44,7 @@ LogLine.ParseLogLevel("[XYZ]: Overly specific, out of context message")
 
 The log level of a log line is quite verbose. To reduce the disk space needed to store the log lines, a short format is developed: `"[]:"`.
 
-The encoded log level is simple mapping of a log level to a number:
+The encoded log level is a simple mapping of a log level to a number:
 
 - `Trace` - `0`
 - `Debug` - `1`
diff --git a/exercises/concept/logs-logs-logs/.meta/config.json b/exercises/concept/logs-logs-logs/.meta/config.json
index e1f564f856..abf302b96c 100644
--- a/exercises/concept/logs-logs-logs/.meta/config.json
+++ b/exercises/concept/logs-logs-logs/.meta/config.json
@@ -1,4 +1,10 @@
 {
+  "contributors": [
+    {
+      "github_username": "valentin-p",
+      "exercism_username": "valentin-p"
+    }
+  ],
   "authors": [
     {
       "github_username": "ErikSchierboom",

From 437304c8af4b3afd2c54ccc6bad56fdd2e920f08 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 22 Dec 2020 15:09:00 +0100
Subject: [PATCH 286/327] Add clarification that new instances are unique

---
 concepts/classes/about.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/concepts/classes/about.md b/concepts/classes/about.md
index a5b951d5db..9acdffcc5b 100644
--- a/concepts/classes/about.md
+++ b/concepts/classes/about.md
@@ -18,7 +18,7 @@ class Car
 {
 }
 
-// Create two car instances
+// Create two (unique) car instances
 var myCar = new Car();
 var yourCar = new Car();
 ```

From 9eba3de52da0d8303050a0c21be419178c3f37b0 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 22 Dec 2020 15:13:51 +0100
Subject: [PATCH 287/327] Revert change to classes concept documentation

---
 concepts/classes/about.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/concepts/classes/about.md b/concepts/classes/about.md
index 9acdffcc5b..a5b951d5db 100644
--- a/concepts/classes/about.md
+++ b/concepts/classes/about.md
@@ -18,7 +18,7 @@ class Car
 {
 }
 
-// Create two (unique) car instances
+// Create two car instances
 var myCar = new Car();
 var yourCar = new Car();
 ```

From 4a8cf433e0bcfc0db471a6fdeeb1c68cca1b7c9a Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 22 Dec 2020 15:17:09 +0100
Subject: [PATCH 288/327] Do-while loop context

---
 concepts/do-while-loops/about.md | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/concepts/do-while-loops/about.md b/concepts/do-while-loops/about.md
index 1a2d5d8f54..be7bfe5c4b 100644
--- a/concepts/do-while-loops/about.md
+++ b/concepts/do-while-loops/about.md
@@ -1,5 +1,4 @@
-TODO: clarify context for do-while loop
-A closely related construct is the `do` loop:
+To repeatedly execute logic, one can use loops. If the code in a loop should always be executed at least one, a `do/while` loop can be used:
 
 ```csharp
 int x = 0;

From b86a8358c486e86d149ee723cf9a4904df5c3b3c Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 22 Dec 2020 16:02:56 +0100
Subject: [PATCH 289/327] Fix typo in named-arguments concept doc

---
 concepts/named-arguments/about.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/concepts/named-arguments/about.md b/concepts/named-arguments/about.md
index 7d81482cfb..149ed2a78b 100644
--- a/concepts/named-arguments/about.md
+++ b/concepts/named-arguments/about.md
@@ -1,4 +1,4 @@
-TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case
+TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providing a more focused context in each case
 [_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
 - The number of parameters

From 15cf6bc5f7233de28af9fd23232a3778d6137b20 Mon Sep 17 00:00:00 2001
From: Taiyab Raja 
Date: Fri, 8 Jan 2021 13:40:51 +0000
Subject: [PATCH 290/327] Minor tweaks to Boolean instructions.

* Minor tweaks to Boolean instructions.

* [CI] Format code

* Update instructions.md

Co-authored-by: github-actions[bot] 
Co-authored-by: Erik Schierboom 
---
 .../annalyns-infiltration/.docs/instructions.md    | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/.docs/instructions.md b/exercises/concept/annalyns-infiltration/.docs/instructions.md
index 2f02278acb..22711a8e42 100644
--- a/exercises/concept/annalyns-infiltration/.docs/instructions.md
+++ b/exercises/concept/annalyns-infiltration/.docs/instructions.md
@@ -1,13 +1,17 @@
-In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing. The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest. Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest.
+In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing.
+
+The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest.
+
+Annalyn will try to find and free her best friend, optionally taking her dog with her on this quest.
 
 After some time spent following her best friend's trail, she finds the camp in which her best friend is imprisoned. It turns out there are two kidnappers: a mighty knight and a cunning archer.
 
 Having found the kidnappers, Annalyn considers which of the following actions she can engage in:
 
-- Fast attack: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable.
-- Spy: the group can be spied upon if at least one of them is awake. Otherwise, spying is a waste of time.
-- Signal prisoner: the prisoner can be signalled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message.
-- Free prisoner: if the prisoner is awake and the other two characters are sleeping, a sneaky entry into the camp can free the prisoner. This won't work if the prisoner is sleeping, as the prisoner will be startled by the sudden appearance of her friend and the knight and archer will be awoken. The prisoner can also be freed if the archer is sleeping and Annalyn has her pet dog with her, as the knight will be scared by the dog and will withdraw, and the archer can't equip his bow fast enough to prevent the prisoner from being freed.
+- _Fast attack_: a fast attack can be made if the knight is sleeping, as it takes time for him to get his armor on, so he will be vulnerable.
+- _Spy_: the group can be spied upon if at least one of them is awake. Otherwise, spying is a waste of time.
+- _Signal prisoner_: the prisoner can be signalled using bird sounds if the prisoner is awake and the archer is sleeping, as archers are trained in bird signaling so they could intercept the message.
+- _Free prisoner_: if the prisoner is awake and the other two characters are sleeping, a sneaky entry into the camp can free the prisoner. This won't work if the prisoner is sleeping, as the prisoner will be startled by the sudden appearance of her friend and the knight and archer will be awoken. The prisoner can also be freed if the archer is sleeping and Annalyn has her pet dog with her, as the knight will be scared by the dog and will withdraw, and the archer can't equip his bow fast enough to prevent the prisoner from being freed.
 
 You have four tasks: to implement the logic for determining if the above actions are available based on the state of the three characters found in the forest and whether Annalyn's pet dog is present or not.
 

From 0d28c7d2d92a6006d5a02ee0dafba9d6ad494831 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 12 Jan 2021 10:11:32 +0100
Subject: [PATCH 291/327] Cleanup instructions headings

---
 .../concept/annalyns-infiltration/.docs/introduction.md   | 2 --
 .../concept/attack-of-the-trolls/.docs/introduction.md    | 4 ++--
 .../concept/authentication-system/.docs/introduction.md   | 6 +++---
 .../beauty-salon-goes-global/.docs/introduction.md        | 4 ++--
 exercises/concept/bird-watcher/.docs/introduction.md      | 6 +++---
 .../concept/booking-up-for-beauty/.docs/introduction.md   | 2 --
 .../concept/building-telemetry/.docs/introduction.md      | 2 --
 .../concept/calculator-conundrum/.docs/introduction.md    | 2 --
 exercises/concept/cars-assemble/.docs/introduction.md     | 4 ++--
 .../concept/developer-privileges/.docs/introduction.md    | 2 --
 exercises/concept/elons-toys/.docs/introduction.md        | 2 --
 exercises/concept/faceid-2/.docs/introduction.md          | 4 ++--
 .../concept/football-match-reports/.docs/introduction.md  | 2 --
 .../concept/high-school-sweethearts/.docs/introduction.md | 4 ++--
 .../hyper-optimized-telemetry/.docs/introduction.md       | 2 --
 exercises/concept/hyperia-forex/.docs/introduction.md     | 2 --
 .../hyperinflation-hits-hyperia/.docs/introduction.md     | 2 --
 .../concept/instruments-of-texas/.docs/introduction.md    | 4 ++--
 .../concept/interest-is-interesting/.docs/introduction.md | 6 +++---
 .../.docs/introduction.md                                 | 2 --
 .../concept/land-grab-in-space/.docs/introduction.md      | 2 --
 exercises/concept/log-levels/.docs/introduction.md        | 2 --
 exercises/concept/logs-logs-logs/.docs/introduction.md    | 2 --
 .../lucians-luscious-lasagna/.docs/introduction.md        | 2 --
 exercises/concept/need-for-speed/.docs/introduction.md    | 2 --
 .../object-relational-mapping/.docs/introduction.md       | 2 --
 exercises/concept/orm-in-one-go/.docs/introduction.md     | 2 --
 exercises/concept/parsing-log-files/.docs/introduction.md | 2 --
 .../concept/phone-number-analysis/.docs/introduction.md   | 2 --
 .../red-vs-blue-darwin-style/.docs/introduction.md        | 2 --
 .../concept/remote-control-cleanup/.docs/introduction.md  | 2 --
 .../remote-control-competition/.docs/introduction.md      | 4 ++--
 exercises/concept/roll-the-die/.docs/introduction.md      | 2 --
 .../secure-munchester-united/.docs/introduction.md        | 2 --
 exercises/concept/squeaky-clean/.docs/introduction.md     | 4 ++--
 .../concept/the-weather-in-deather/.docs/introduction.md  | 8 ++++----
 .../concept/tim-from-marketing/.docs/introduction.md      | 2 --
 .../tracks-on-tracks-on-tracks/.docs/introduction.md      | 4 ++--
 exercises/concept/weighing-machine/.docs/introduction.md  | 2 --
 .../concept/wizards-and-warriors-2/.docs/introduction.md  | 6 +++---
 .../concept/wizards-and-warriors/.docs/introduction.md    | 2 --
 41 files changed, 34 insertions(+), 88 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/.docs/introduction.md b/exercises/concept/annalyns-infiltration/.docs/introduction.md
index fe13978ed3..5341d27350 100644
--- a/exercises/concept/annalyns-infiltration/.docs/introduction.md
+++ b/exercises/concept/annalyns-infiltration/.docs/introduction.md
@@ -1,5 +1,3 @@
-## booleans
-
 Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`.
 
 C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR).
diff --git a/exercises/concept/attack-of-the-trolls/.docs/introduction.md b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
index 01ae714731..a41e13147a 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/introduction.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
@@ -1,4 +1,4 @@
-## attributes
+## Attributes
 
 A [C# `Attribute`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/) provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) declarations.
 
@@ -17,7 +17,7 @@ This declarative metadata only associates additional structured information to t
 
 There is many [predefined and reserved attributes](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#conditional-attribute), for example: `Flags`, `Obsolete`, `Conditional`, each has a specific that can be looked up on the C# documentation. Note that the full name of an attribute like [`Flags`](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0) is `FlagsAttribute` by convention, but the suffix _Attribute_ can be omitted when applied on a declaration.
 
-## flag-enums
+## Flag Enums
 
 The C# [`enum` type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) represents a fixed set of named constants (an enumeration).
 
diff --git a/exercises/concept/authentication-system/.docs/introduction.md b/exercises/concept/authentication-system/.docs/introduction.md
index c9460e3739..25ccf76af7 100644
--- a/exercises/concept/authentication-system/.docs/introduction.md
+++ b/exercises/concept/authentication-system/.docs/introduction.md
@@ -1,4 +1,4 @@
-## constants
+## Constants
 
 The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
 
@@ -19,7 +19,7 @@ public MyClass(int num)
 }
 ```
 
-## readonly-collections
+## Readonly Collections
 
 While the `readonly` modifier prevents the value or reference in a field from being overwritten, it offers no protection for the members of a reference type.
 
@@ -40,6 +40,6 @@ The Base Class Library (BCL) provides some readonly versions of collections wher
 - `ReadOnlyDictionary` exposes a `Dictionary` as read-only.
 - `ReadOnlyCollection` exposes a `List` as read-only.
 
-## defensive-copying
+## Defensive Copying
 
 In security sensitive situations (or even simply on a large code-base where developers have different priorities and agendas) you should avoid allowing a class's public API to be circumvented by accepting and storing a method's mutable parameters or by exposing a mutable member of a class through a return value or as an `out` parameter.
diff --git a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
index 8ea7c01e80..b3cc1dbcf6 100644
--- a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
+++ b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
@@ -1,8 +1,8 @@
-## time
+## Time
 
 The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`.
 
-## timezone
+## Timezone
 
 The `TimeZoneInfo` class provides routines for handling the differences between time zones. The `TimeZoneInfo` class also contains methods that facilitate dealing with daylight saving time.
 
diff --git a/exercises/concept/bird-watcher/.docs/introduction.md b/exercises/concept/bird-watcher/.docs/introduction.md
index 0dfe9b1a7c..95142f5c7e 100644
--- a/exercises/concept/bird-watcher/.docs/introduction.md
+++ b/exercises/concept/bird-watcher/.docs/introduction.md
@@ -1,4 +1,4 @@
-## arrays
+## Arrays
 
 In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
 
@@ -24,7 +24,7 @@ int[] threeIntsV3 = { 4, 9, 7 };
 
 Arrays can be manipulated by either calling an array instance's methods or properties, or by using the static methods defined in the `Array` class.
 
-## foreach-loops
+## Foreach Loops
 
 The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over _all_ its values using a `foreach` loop:
 
@@ -40,7 +40,7 @@ foreach (char vowel in vowels)
 // => aeiou
 ```
 
-## for-loops
+## For Loops
 
 If you want more control over which values to iterate over, a `for` loop can be used:
 
diff --git a/exercises/concept/booking-up-for-beauty/.docs/introduction.md b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
index e369ed1483..7ba7a7786f 100644
--- a/exercises/concept/booking-up-for-beauty/.docs/introduction.md
+++ b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
@@ -1,5 +1,3 @@
-## datetimes
-
 A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`.
 
 The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`.
diff --git a/exercises/concept/building-telemetry/.docs/introduction.md b/exercises/concept/building-telemetry/.docs/introduction.md
index c1a247b70c..1c42283f86 100644
--- a/exercises/concept/building-telemetry/.docs/introduction.md
+++ b/exercises/concept/building-telemetry/.docs/introduction.md
@@ -1,5 +1,3 @@
-## parameters
-
 This exercise discusses some details of method parameters and their use in C#.
 
 Parameters convey information from a calling method to a called method.
diff --git a/exercises/concept/calculator-conundrum/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md
index f8a9c5664f..002ea03980 100644
--- a/exercises/concept/calculator-conundrum/.docs/introduction.md
+++ b/exercises/concept/calculator-conundrum/.docs/introduction.md
@@ -1,5 +1,3 @@
-## exceptions
-
 Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes.
 
 In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown.
diff --git a/exercises/concept/cars-assemble/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md
index f695c2df7c..69949b8590 100644
--- a/exercises/concept/cars-assemble/.docs/introduction.md
+++ b/exercises/concept/cars-assemble/.docs/introduction.md
@@ -1,4 +1,4 @@
-## numbers
+## Numbers
 
 There are two different types of numbers in C#:
 
@@ -16,7 +16,7 @@ C# has two types of numeric conversions:
 
 As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion.
 
-## if-statements
+## If Statements
 
 In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement:
 
diff --git a/exercises/concept/developer-privileges/.docs/introduction.md b/exercises/concept/developer-privileges/.docs/introduction.md
index e382ae4256..25b3b07ef5 100644
--- a/exercises/concept/developer-privileges/.docs/introduction.md
+++ b/exercises/concept/developer-privileges/.docs/introduction.md
@@ -1,5 +1,3 @@
-## object-initializers
-
 Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets:
 
 ```csharp
diff --git a/exercises/concept/elons-toys/.docs/introduction.md b/exercises/concept/elons-toys/.docs/introduction.md
index 51cd99cecd..e3770a9229 100644
--- a/exercises/concept/elons-toys/.docs/introduction.md
+++ b/exercises/concept/elons-toys/.docs/introduction.md
@@ -1,5 +1,3 @@
-## classes
-
 The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_.
 
 Access to members can be restricted through access modifiers, the two most common ones being:
diff --git a/exercises/concept/faceid-2/.docs/introduction.md b/exercises/concept/faceid-2/.docs/introduction.md
index 4061dd9f19..b6353dab95 100644
--- a/exercises/concept/faceid-2/.docs/introduction.md
+++ b/exercises/concept/faceid-2/.docs/introduction.md
@@ -1,4 +1,4 @@
-## equality
+## Equality
 
 Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`.
 
@@ -20,6 +20,6 @@ The HashCode library API documentation discusses the best way to generate a hash
 
 The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be immutable. Other approaches run the risk of creating gotchas for maintainers.
 
-## sets
+## Sets
 
 The `HashSet` library class provides a good mechanism for storing unique values.
diff --git a/exercises/concept/football-match-reports/.docs/introduction.md b/exercises/concept/football-match-reports/.docs/introduction.md
index d57cfbfa6d..8395a6f1c9 100644
--- a/exercises/concept/football-match-reports/.docs/introduction.md
+++ b/exercises/concept/football-match-reports/.docs/introduction.md
@@ -1,5 +1,3 @@
-## switch-statements
-
 Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program".
 
 The mechanism involves the following keywords: `switch`, `case`, `break` and `default`.
diff --git a/exercises/concept/high-school-sweethearts/.docs/introduction.md b/exercises/concept/high-school-sweethearts/.docs/introduction.md
index d590a2369b..ca33e2d711 100644
--- a/exercises/concept/high-school-sweethearts/.docs/introduction.md
+++ b/exercises/concept/high-school-sweethearts/.docs/introduction.md
@@ -1,4 +1,4 @@
-## string-formatting
+## String Formatting
 
 There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation.
 
@@ -58,7 +58,7 @@ Each thread has a default culture `Thread.CurrentThread.CurrentCulture` encapsul
 
 `CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture.
 
-## verbatim-strings
+## Verbatim Strings
 
 Verbatim strings allow multi-line strings. They are introduced with an @.
 
diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
index 2a86bc79da..a134fd0930 100644
--- a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
+++ b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
@@ -1,5 +1,3 @@
-## integral-numbers
-
 C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types.
 
 The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits.
diff --git a/exercises/concept/hyperia-forex/.docs/introduction.md b/exercises/concept/hyperia-forex/.docs/introduction.md
index 4d09c2ef8d..9c72dea800 100644
--- a/exercises/concept/hyperia-forex/.docs/introduction.md
+++ b/exercises/concept/hyperia-forex/.docs/introduction.md
@@ -1,5 +1,3 @@
-## operator-overloading
-
 The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_.
 
 Most operators have the form:
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
index 76fc34f288..a2313bf95e 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
+++ b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
@@ -1,5 +1,3 @@
-## overflow
-
 Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type.
 
 Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances.
diff --git a/exercises/concept/instruments-of-texas/.docs/introduction.md b/exercises/concept/instruments-of-texas/.docs/introduction.md
index f304c84453..263dee13d5 100644
--- a/exercises/concept/instruments-of-texas/.docs/introduction.md
+++ b/exercises/concept/instruments-of-texas/.docs/introduction.md
@@ -1,10 +1,10 @@
-## user-defined-exceptions
+## User Defined Exceptions
 
 A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise.
 
 User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines.
 
-## exception-filtering
+## Exception Filtering
 
 `when` is the key word in filtering exceptions. It is placed after the catch
 statement and can take a boolean expression containing any values in scope at the time. If the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked.
diff --git a/exercises/concept/interest-is-interesting/.docs/introduction.md b/exercises/concept/interest-is-interesting/.docs/introduction.md
index 1966481c64..cfde2d2adc 100644
--- a/exercises/concept/interest-is-interesting/.docs/introduction.md
+++ b/exercises/concept/interest-is-interesting/.docs/introduction.md
@@ -1,4 +1,4 @@
-## floating-point-numbers
+## Floating Point Numbers
 
 A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.
 
@@ -12,7 +12,7 @@ C# has three floating-point types:
 
 As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded).
 
-## while-loops
+## While Loops
 
 In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here:
 
@@ -26,7 +26,7 @@ while (x > 10)
 }
 ```
 
-## do-while-loops
+## Do While Loops
 
 An less commonly used alternative to the above syntax is a `do-while` loop:
 
diff --git a/exercises/concept/international-calling-connoisseur/.docs/introduction.md b/exercises/concept/international-calling-connoisseur/.docs/introduction.md
index 8967cbfea8..91a2a23020 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/introduction.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/introduction.md
@@ -1,5 +1,3 @@
-## dictionaries
-
 A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages.
 
 A dictionary can be created as follows:
diff --git a/exercises/concept/land-grab-in-space/.docs/introduction.md b/exercises/concept/land-grab-in-space/.docs/introduction.md
index f214c303f1..6b1142d00f 100644
--- a/exercises/concept/land-grab-in-space/.docs/introduction.md
+++ b/exercises/concept/land-grab-in-space/.docs/introduction.md
@@ -1,5 +1,3 @@
-## structs
-
 C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.
 
 ```csharp
diff --git a/exercises/concept/log-levels/.docs/introduction.md b/exercises/concept/log-levels/.docs/introduction.md
index 2ededb0096..d7d72cd2ec 100644
--- a/exercises/concept/log-levels/.docs/introduction.md
+++ b/exercises/concept/log-levels/.docs/introduction.md
@@ -1,5 +1,3 @@
-## strings
-
 A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance:
 
 ```csharp
diff --git a/exercises/concept/logs-logs-logs/.docs/introduction.md b/exercises/concept/logs-logs-logs/.docs/introduction.md
index 956e314c06..9f383a26bb 100644
--- a/exercises/concept/logs-logs-logs/.docs/introduction.md
+++ b/exercises/concept/logs-logs-logs/.docs/introduction.md
@@ -1,5 +1,3 @@
-## enums
-
 The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows:
 
 ```csharp
diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
index f77dcbdc9f..a0da40de82 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
@@ -1,5 +1,3 @@
-## basics
-
 C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent:
 
 ```csharp
diff --git a/exercises/concept/need-for-speed/.docs/introduction.md b/exercises/concept/need-for-speed/.docs/introduction.md
index f531f19eaa..1fbd17c9ef 100644
--- a/exercises/concept/need-for-speed/.docs/introduction.md
+++ b/exercises/concept/need-for-speed/.docs/introduction.md
@@ -1,5 +1,3 @@
-## constructors
-
 Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name.
 
 ```csharp
diff --git a/exercises/concept/object-relational-mapping/.docs/introduction.md b/exercises/concept/object-relational-mapping/.docs/introduction.md
index 0ef5a70fe6..ffeafbf696 100644
--- a/exercises/concept/object-relational-mapping/.docs/introduction.md
+++ b/exercises/concept/object-relational-mapping/.docs/introduction.md
@@ -1,3 +1 @@
-## resource-cleanup
-
 If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset.
diff --git a/exercises/concept/orm-in-one-go/.docs/introduction.md b/exercises/concept/orm-in-one-go/.docs/introduction.md
index 7850b02a3e..ee0bef510d 100644
--- a/exercises/concept/orm-in-one-go/.docs/introduction.md
+++ b/exercises/concept/orm-in-one-go/.docs/introduction.md
@@ -1,5 +1,3 @@
-## resource-lifetime
-
 You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations.
 
 There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement.
diff --git a/exercises/concept/parsing-log-files/.docs/introduction.md b/exercises/concept/parsing-log-files/.docs/introduction.md
index d7d01daf72..1256179199 100644
--- a/exercises/concept/parsing-log-files/.docs/introduction.md
+++ b/exercises/concept/parsing-log-files/.docs/introduction.md
@@ -1,3 +1 @@
-## regular-expressions
-
 The .NET base class libraries provide the `Regex` class for processing of regular expressions.
diff --git a/exercises/concept/phone-number-analysis/.docs/introduction.md b/exercises/concept/phone-number-analysis/.docs/introduction.md
index c81d436cf5..88510ef0c5 100644
--- a/exercises/concept/phone-number-analysis/.docs/introduction.md
+++ b/exercises/concept/phone-number-analysis/.docs/introduction.md
@@ -1,5 +1,3 @@
-## tuples
-
 In C#, a tuple is a data structure which organizes data, holding two or more fields
 of any type.
 
diff --git a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
index ea0abd4d3b..ccfd49113a 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
+++ b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
@@ -1,5 +1,3 @@
-## namespaces
-
 Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base.
 
 The syntax is as follows:
diff --git a/exercises/concept/remote-control-cleanup/.docs/introduction.md b/exercises/concept/remote-control-cleanup/.docs/introduction.md
index 8ac8f8d2eb..1edafdd14b 100644
--- a/exercises/concept/remote-control-cleanup/.docs/introduction.md
+++ b/exercises/concept/remote-control-cleanup/.docs/introduction.md
@@ -1,5 +1,3 @@
-## nested-types
-
 C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax.
 
 ```csharp
diff --git a/exercises/concept/remote-control-competition/.docs/introduction.md b/exercises/concept/remote-control-competition/.docs/introduction.md
index 2eea97a55b..47bb2656c6 100644
--- a/exercises/concept/remote-control-competition/.docs/introduction.md
+++ b/exercises/concept/remote-control-competition/.docs/introduction.md
@@ -1,4 +1,4 @@
-## interfaces
+## Interfaces
 
 An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion.
 
@@ -33,6 +33,6 @@ All operations defined by the interface must be implemented.
 
 Interfaces can contain instance methods and properties amongst other members
 
-## ordering
+## Ordering
 
 The `IComparable` interface can be implemented where a default generic sort order in collections is required.
diff --git a/exercises/concept/roll-the-die/.docs/introduction.md b/exercises/concept/roll-the-die/.docs/introduction.md
index 0aaffebbb6..264aec91ec 100644
--- a/exercises/concept/roll-the-die/.docs/introduction.md
+++ b/exercises/concept/roll-the-die/.docs/introduction.md
@@ -1,3 +1 @@
-## randomness
-
 In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case.
diff --git a/exercises/concept/secure-munchester-united/.docs/introduction.md b/exercises/concept/secure-munchester-united/.docs/introduction.md
index a739d842fe..d05ff9408e 100644
--- a/exercises/concept/secure-munchester-united/.docs/introduction.md
+++ b/exercises/concept/secure-munchester-united/.docs/introduction.md
@@ -1,5 +1,3 @@
-## casting
-
 Casting and type conversion are different ways of changing an expression from one data type to another.
 
 An expression can be cast to another type with the cast operator `()`.
diff --git a/exercises/concept/squeaky-clean/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md
index 3b1e88f8e8..92830e8874 100644
--- a/exercises/concept/squeaky-clean/.docs/introduction.md
+++ b/exercises/concept/squeaky-clean/.docs/introduction.md
@@ -1,4 +1,4 @@
-## chars
+## Chars
 
 The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text.
 Multiple `char`s can comprise a string such as `"word"` or `char`s can be
@@ -11,7 +11,7 @@ e.g. ancient greek `'β'`.
 There are many builtin library methods to inspect and manipulate `char`s. These
 can be found as static methods of the `System.Char` class.
 
-## string-builder
+## String Builder
 
 `char`s are sometimes used in conjunction with a `StringBuilder` object.
 This object has methods that allow a string to be constructed
diff --git a/exercises/concept/the-weather-in-deather/.docs/introduction.md b/exercises/concept/the-weather-in-deather/.docs/introduction.md
index 22b6561b76..c79b3ffd0d 100644
--- a/exercises/concept/the-weather-in-deather/.docs/introduction.md
+++ b/exercises/concept/the-weather-in-deather/.docs/introduction.md
@@ -1,4 +1,4 @@
-## expression-bodied-members
+## Expression Bodied Members
 
 Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements.
 
@@ -10,7 +10,7 @@ public int Times3(int input) => input * 3;
 public int Interesting => 1729;
 ```
 
-## ternary-operators
+## Conditionals Ternary
 
 Ternary operators allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone.
 
@@ -22,7 +22,7 @@ int max = a > b ? a : b;
 // => 4
 ```
 
-## throw-expressions
+## Throw Expressions
 
 `throw` expressions are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions.
 
@@ -30,7 +30,7 @@ int max = a > b ? a : b;
 string trimmed = str == null ? throw new ArgumentException() : str.Trim();
 ```
 
-## switch-expressions
+## Switch Expressions
 
 A switch expression can match a value to one case in a set of patterns and return the associated value or take the associated action. The association is denoted by the `=>` symbol. In addition, each pattern can have an optional case guard introduced with the `when` keyword. The case guard expression must evaluate to true for that "arm" of the switch to be selected. The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found.
 
diff --git a/exercises/concept/tim-from-marketing/.docs/introduction.md b/exercises/concept/tim-from-marketing/.docs/introduction.md
index 7c125eff5a..6ce9868e2e 100644
--- a/exercises/concept/tim-from-marketing/.docs/introduction.md
+++ b/exercises/concept/tim-from-marketing/.docs/introduction.md
@@ -1,5 +1,3 @@
-## nullability
-
 In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values.
 
 Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`).
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
index af3cae91da..18d037e5e1 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
@@ -1,4 +1,4 @@
-## lists
+## Lists
 
 Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists.
 
@@ -8,6 +8,6 @@ Items can be added to and removed from lists. They grow and shrink as necessary.
 var listOfStrings = new List();
 ```
 
-## generic-types
+## Generic Types
 
 A collection definition typically includes a place holder in angle brackets, often `T` by convention. Such a collection is referred to as a generic type. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings.
diff --git a/exercises/concept/weighing-machine/.docs/introduction.md b/exercises/concept/weighing-machine/.docs/introduction.md
index eccdbea49a..1405dddcca 100644
--- a/exercises/concept/weighing-machine/.docs/introduction.md
+++ b/exercises/concept/weighing-machine/.docs/introduction.md
@@ -1,5 +1,3 @@
-## properties
-
 A property in C# is a member of a class that provides access to data within that class.
 Callers can set or retrieve (get) the data. Properties can be either auto-implemented or
 have a backing field. They comprise a set accessor and/or a get accessor.
diff --git a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
index 0aa9b2a207..0fffa16375 100644
--- a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
+++ b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
@@ -1,4 +1,4 @@
-## method-overloading
+## Method Overloading
 
 _Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
@@ -9,7 +9,7 @@ There is no method overloading based on the return type.
 
 The compiler will automatically infer which overloaded method to call based on the number of parameters and their type.
 
-## optional-parameters
+## Optional Parameters
 
 A method parameter can be made optional by assigning it a default value. When calling a method with optional parameters, the caller is not required to pass a value for them. If no value is passed for an optional parameter, its default value will be used.
 
@@ -28,7 +28,7 @@ Card.NewYear();  // => "Happy 2020!"
 Card.Card(1999); // => "Happy 1999!"
 ```
 
-## named-arguments
+## Named Arguments
 
 So far we have seen that the arguments passed into a method are matched to the method are matched to the method's declared parameters based on position. An alternative approach, particularly where a routine takes a large number of arguments, the caller can match arguments by specifying the declared parameter's identifier.
 
diff --git a/exercises/concept/wizards-and-warriors/.docs/introduction.md b/exercises/concept/wizards-and-warriors/.docs/introduction.md
index 6976e1bc54..32a4f8d3b0 100644
--- a/exercises/concept/wizards-and-warriors/.docs/introduction.md
+++ b/exercises/concept/wizards-and-warriors/.docs/introduction.md
@@ -1,5 +1,3 @@
-## inheritance
-
 In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class.
 
 Parent classes can provide functionality to derived classes in three ways:

From 3e87a04e31c9adf061303c34764b7fac74442075 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 12 Jan 2021 10:33:53 +0100
Subject: [PATCH 292/327] Add concept introductions

* Add concept introductions

* [CI] Format code

Co-authored-by: github-actions[bot] 
---
 concepts/arrays/introduction.md               |  23 ++++
 concepts/attributes/introduction.md           |  16 +++
 concepts/basics/introduction.md               |  53 +++++++++
 concepts/bit-manipulation/introduction.md     |   1 +
 concepts/booleans/introduction.md             |   3 +
 concepts/casting/introduction.md              |  35 ++++++
 concepts/chars/introduction.md                |  10 ++
 concepts/classes/introduction.md              |  66 ++++++++++++
 concepts/compound-assignment/introduction.md  |   1 +
 concepts/const-readonly/introduction.md       |   1 +
 concepts/constants/introduction.md            |  18 ++++
 concepts/constructors/introduction.md         |  36 +++++++
 concepts/datetimes/introduction.md            |   5 +
 concepts/defensive-copying/introduction.md    |   1 +
 concepts/dictionaries/introduction.md         |  60 +++++++++++
 concepts/do-while-loops/introduction.md       |  11 ++
 concepts/enums/introduction.md                |  22 ++++
 concepts/equality/introduction.md             |  19 ++++
 concepts/exception-filtering/introduction.md  |  17 +++
 concepts/exceptions/introduction.md           |  46 ++++++++
 concepts/explicit-casts/introduction.md       |   1 +
 .../expression-bodied-members/introduction.md |   9 ++
 concepts/flag-enums/introduction.md           |  27 +++++
 .../floating-point-numbers/introduction.md    |  11 ++
 concepts/for-loops/introduction.md            |  13 +++
 concepts/foreach-loops/introduction.md        |  13 +++
 concepts/generic-types/introduction.md        |   1 +
 concepts/if-statements/introduction.md        |  20 ++++
 concepts/indexers/introduction.md             |   1 +
 concepts/inheritance/introduction.md          | 102 ++++++++++++++++++
 concepts/integral-numbers/introduction.md     |  34 ++++++
 concepts/interfaces/introduction.md           |  32 ++++++
 concepts/lists/introduction.md                |   7 ++
 concepts/memory-allocation/introduction.md    |   1 +
 concepts/method-overloading/introduction.md   |   8 ++
 concepts/named-arguments/introduction.md      |  15 +++
 concepts/namespaces/introduction.md           |  52 +++++++++
 concepts/nested-types/introduction.md         |  18 ++++
 concepts/nullability/introduction.md          |  76 +++++++++++++
 concepts/numbers/introduction.md              |  15 +++
 concepts/object-initializers/introduction.md  |  27 +++++
 concepts/operator-overloading/introduction.md |  15 +++
 concepts/optional-parameters/introduction.md  |  16 +++
 concepts/ordering/introduction.md             |   1 +
 concepts/overflow/introduction.md             |  21 ++++
 concepts/parameters/introduction.md           |  47 ++++++++
 concepts/properties/introduction.md           |  38 +++++++
 concepts/randomness/introduction.md           |   1 +
 concepts/readonly-collections/introduction.md |  18 ++++
 concepts/regular-expressions/introduction.md  |   1 +
 concepts/resource-cleanup/introduction.md     |   1 +
 concepts/resource-lifetime/introduction.md    |  30 ++++++
 concepts/sets/introduction.md                 |   1 +
 concepts/string-builder/introduction.md       |   4 +
 concepts/string-formatting/introduction.md    |  57 ++++++++++
 concepts/string-interpolation/introduction.md |   1 +
 concepts/strings/introduction.md              |  23 ++++
 concepts/structs/introduction.md              |  28 +++++
 concepts/switch-expressions/introduction.md   |  17 +++
 concepts/switch-statements/introduction.md    |  42 ++++++++
 concepts/ternary-operators/introduction.md    |   9 ++
 concepts/throw-expressions/introduction.md    |   5 +
 concepts/time/introduction.md                 |   1 +
 concepts/timezone/introduction.md             |   5 +
 concepts/tuples/introduction.md               |  51 +++++++++
 .../user-defined-exceptions/introduction.md   |   3 +
 concepts/varargs/introduction.md              |   1 +
 concepts/verbatim-strings/introduction.md     |   8 ++
 concepts/while-loops/introduction.md          |  11 ++
 69 files changed, 1383 insertions(+)
 create mode 100644 concepts/arrays/introduction.md
 create mode 100644 concepts/attributes/introduction.md
 create mode 100644 concepts/basics/introduction.md
 create mode 100644 concepts/bit-manipulation/introduction.md
 create mode 100644 concepts/booleans/introduction.md
 create mode 100644 concepts/casting/introduction.md
 create mode 100644 concepts/chars/introduction.md
 create mode 100644 concepts/classes/introduction.md
 create mode 100644 concepts/compound-assignment/introduction.md
 create mode 100644 concepts/const-readonly/introduction.md
 create mode 100644 concepts/constants/introduction.md
 create mode 100644 concepts/constructors/introduction.md
 create mode 100644 concepts/datetimes/introduction.md
 create mode 100644 concepts/defensive-copying/introduction.md
 create mode 100644 concepts/dictionaries/introduction.md
 create mode 100644 concepts/do-while-loops/introduction.md
 create mode 100644 concepts/enums/introduction.md
 create mode 100644 concepts/equality/introduction.md
 create mode 100644 concepts/exception-filtering/introduction.md
 create mode 100644 concepts/exceptions/introduction.md
 create mode 100644 concepts/explicit-casts/introduction.md
 create mode 100644 concepts/expression-bodied-members/introduction.md
 create mode 100644 concepts/flag-enums/introduction.md
 create mode 100644 concepts/floating-point-numbers/introduction.md
 create mode 100644 concepts/for-loops/introduction.md
 create mode 100644 concepts/foreach-loops/introduction.md
 create mode 100644 concepts/generic-types/introduction.md
 create mode 100644 concepts/if-statements/introduction.md
 create mode 100644 concepts/indexers/introduction.md
 create mode 100644 concepts/inheritance/introduction.md
 create mode 100644 concepts/integral-numbers/introduction.md
 create mode 100644 concepts/interfaces/introduction.md
 create mode 100644 concepts/lists/introduction.md
 create mode 100644 concepts/memory-allocation/introduction.md
 create mode 100644 concepts/method-overloading/introduction.md
 create mode 100644 concepts/named-arguments/introduction.md
 create mode 100644 concepts/namespaces/introduction.md
 create mode 100644 concepts/nested-types/introduction.md
 create mode 100644 concepts/nullability/introduction.md
 create mode 100644 concepts/numbers/introduction.md
 create mode 100644 concepts/object-initializers/introduction.md
 create mode 100644 concepts/operator-overloading/introduction.md
 create mode 100644 concepts/optional-parameters/introduction.md
 create mode 100644 concepts/ordering/introduction.md
 create mode 100644 concepts/overflow/introduction.md
 create mode 100644 concepts/parameters/introduction.md
 create mode 100644 concepts/properties/introduction.md
 create mode 100644 concepts/randomness/introduction.md
 create mode 100644 concepts/readonly-collections/introduction.md
 create mode 100644 concepts/regular-expressions/introduction.md
 create mode 100644 concepts/resource-cleanup/introduction.md
 create mode 100644 concepts/resource-lifetime/introduction.md
 create mode 100644 concepts/sets/introduction.md
 create mode 100644 concepts/string-builder/introduction.md
 create mode 100644 concepts/string-formatting/introduction.md
 create mode 100644 concepts/string-interpolation/introduction.md
 create mode 100644 concepts/strings/introduction.md
 create mode 100644 concepts/structs/introduction.md
 create mode 100644 concepts/switch-expressions/introduction.md
 create mode 100644 concepts/switch-statements/introduction.md
 create mode 100644 concepts/ternary-operators/introduction.md
 create mode 100644 concepts/throw-expressions/introduction.md
 create mode 100644 concepts/time/introduction.md
 create mode 100644 concepts/timezone/introduction.md
 create mode 100644 concepts/tuples/introduction.md
 create mode 100644 concepts/user-defined-exceptions/introduction.md
 create mode 100644 concepts/varargs/introduction.md
 create mode 100644 concepts/verbatim-strings/introduction.md
 create mode 100644 concepts/while-loops/introduction.md

diff --git a/concepts/arrays/introduction.md b/concepts/arrays/introduction.md
new file mode 100644
index 0000000000..6007d85ac5
--- /dev/null
+++ b/concepts/arrays/introduction.md
@@ -0,0 +1,23 @@
+In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
+
+```csharp
+// Declare array with explicit size (size is 2)
+int[] twoInts = new int[2];
+
+// Assign second element by index
+twoInts[1] = 8;
+
+// Retrieve the second element by index
+twoInts[1] == 8; // => true
+```
+
+Arrays can also be defined using a shortcut notation that allows you to both create the array and set its value. As the compiler can now tell how many elements the array will have, the length can be omitted:
+
+```csharp
+// Three equivalent ways to declare and initialize an array (size is 3)
+int[] threeIntsV1 = new int[] { 4, 9, 7 };
+int[] threeIntsV2 = new[] { 4, 9, 7 };
+int[] threeIntsV3 = { 4, 9, 7 };
+```
+
+Arrays can be manipulated by either calling an array instance's methods or properties, or by using the static methods defined in the `Array` class.
diff --git a/concepts/attributes/introduction.md b/concepts/attributes/introduction.md
new file mode 100644
index 0000000000..f590e5ecda
--- /dev/null
+++ b/concepts/attributes/introduction.md
@@ -0,0 +1,16 @@
+A [C# `Attribute`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/) provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) declarations.
+
+You can apply an attribute by adding it on the line before the declaration using a `ClassAttribute` and a `FieldAttribute`:
+
+```csharp
+[Class]
+class MyClass
+{
+    [Field]
+    int myField;
+}
+```
+
+This declarative metadata only associates additional structured information to the code and does not modify its behavior, but that metadata is used by other part of the code to change how its target would behave or add, change or remove, restrict some its functionalities.
+
+There is many [predefined and reserved attributes](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/attributes/general#conditional-attribute), for example: `Flags`, `Obsolete`, `Conditional`, each has a specific that can be looked up on the C# documentation. Note that the full name of an attribute like [`Flags`](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0) is `FlagsAttribute` by convention, but the suffix _Attribute_ can be omitted when applied on a declaration.
diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md
new file mode 100644
index 0000000000..a0da40de82
--- /dev/null
+++ b/concepts/basics/introduction.md
@@ -0,0 +1,53 @@
+C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent:
+
+```csharp
+int explicitVar = 10; // Explicitly typed
+var implicitVar = 10; // Implicitly typed
+```
+
+Updating a variable's value is done through the `=` operator. Once defined, a variable's type can never change.
+
+```csharp
+var count = 1; // Assign initial value
+count = 2;     // Update to new value
+
+// Compiler error when assigning different type
+// count = false;
+```
+
+C# is an [object-oriented language][object-oriented-programming] and requires all functions to be defined in a _class_. The `class` keyword is used to define a class. Objects (or _instances_) are created by using the `new` keyword.
+
+```csharp
+class Calculator
+{
+    // ...
+}
+
+var calculator = new Calculator();
+```
+
+A function within a class is referred to as a _method_. Each method can have zero or more parameters. All parameters must be explicitly typed, there is no type inference for parameters. Similarly, the return type must also be made explicit. Values are returned from methods using the `return` keyword. To allow a method to be called by code in other files, the `public` access modifier must be added.
+
+```csharp
+class Calculator
+{
+    public int Add(int x, int y)
+    {
+        return x + y;
+    }
+}
+```
+
+Methods are invoked using dot (`.`) syntax on an instance, specifying the method name to call and passing arguments for each of the method's parameters. Arguments can optionally specify the corresponding parameter's name.
+
+```csharp
+var calculator = new Calculator();
+var sum_v1 = calculator.Add(1, 2);
+var sum_v2 = calculator.Add(x: 1, y: 2);
+```
+
+Scope in C# is defined between the `{` and `}` characters.
+
+C# supports two types of comments. Single line comments are preceded by `//` and multiline comments are inserted between `/*` and `*/`.
+
+[object-oriented-programming]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/object-oriented-programming
diff --git a/concepts/bit-manipulation/introduction.md b/concepts/bit-manipulation/introduction.md
new file mode 100644
index 0000000000..8229d6b196
--- /dev/null
+++ b/concepts/bit-manipulation/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for bit-manipulation concept
diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md
new file mode 100644
index 0000000000..5341d27350
--- /dev/null
+++ b/concepts/booleans/introduction.md
@@ -0,0 +1,3 @@
+Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`.
+
+C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR).
diff --git a/concepts/casting/introduction.md b/concepts/casting/introduction.md
new file mode 100644
index 0000000000..d05ff9408e
--- /dev/null
+++ b/concepts/casting/introduction.md
@@ -0,0 +1,35 @@
+Casting and type conversion are different ways of changing an expression from one data type to another.
+
+An expression can be cast to another type with the cast operator `()`.
+
+```csharp
+long l = 1000L;
+int i = (int)l;
+
+object o = new Random();
+Random r = (Random)o;
+```
+
+If the types are not compatible an instance of `InvalidCastException` is thrown. In the case of numbers this indicates that the receiving type cannot represent the cast value. In the case of classes, one of the types must be derived from the other (this also applies trivially to structs).
+
+An alternative to _casting_ is _type conversion_ using the `is` operator. This is typically applied to reference and nullable types.
+
+```csharp
+object o = new Random();
+if (o is Random rand)
+{
+    int ii = rand.Next();
+    // now, do something random
+}
+```
+
+If you need to detect the precise type of an object then `is` may be a little too permissive as it will return true for a class and any of the classes and interfaces from which it is derived directly or indirectly. `typeof` and `Object.GetType()` are the solution in this case.
+
+```csharp
+object o = new List();
+
+o is ICollection // true
+o.GetType() == typeof(ICollection) // false
+o is List // true
+o.GetType() == typeof(List) // true
+```
diff --git a/concepts/chars/introduction.md b/concepts/chars/introduction.md
new file mode 100644
index 0000000000..cf7285da07
--- /dev/null
+++ b/concepts/chars/introduction.md
@@ -0,0 +1,10 @@
+The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text.
+Multiple `char`s can comprise a string such as `"word"` or `char`s can be
+processed independently. Their literals have single quotes e.g. `'A'`.
+
+C# `char`s support UTF-16 Unicode encoding so in addition to the latin character set
+pretty much all the writing systems in use world can be represented,
+e.g. ancient greek `'β'`.
+
+There are many builtin library methods to inspect and manipulate `char`s. These
+can be found as static methods of the `System.Char` class.
diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md
new file mode 100644
index 0000000000..e3770a9229
--- /dev/null
+++ b/concepts/classes/introduction.md
@@ -0,0 +1,66 @@
+The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_.
+
+Access to members can be restricted through access modifiers, the two most common ones being:
+
+- `public`: the member can be accessed by any code (no restrictions).
+- `private`: the member can only be accessed by code in the same class.
+
+You can think of a class as a template for creating instances of that class. To create an instance of a class (also known as an _object_), the `new` keyword is used:
+
+```csharp
+class Car
+{
+}
+
+// Create two car instances
+var myCar = new Car();
+var yourCar = new Car();
+```
+
+Fields have a type and a name (defined in camelCase) and can be defined anywhere in a class (defined in PascalCase):
+
+```csharp
+class Car
+{
+    // Accessible by anyone
+    public int weight;
+
+    // Only accessible by code in this class
+    private string color;
+}
+```
+
+One can optionally assign an initial value to a field. If a field does _not_ specify an initial value, it wll be set to its type's default value. An instance's field values can be accessed and updated using dot-notation.
+
+```csharp
+class Car
+{
+    // Will be set to specified value
+    public int weight = 2500;
+
+    // Will be set to default value (0)
+    public int year;
+}
+
+var newCar = new Car();
+newCar.weight; // => 2500
+newCar.year;   // => 0
+
+// Update value of the field
+newCar.year = 2018;
+```
+
+Private fields are usually updated as a side-effect of calling a method. Such methods usually don't return any value, in which case the return type should be `void`:
+
+```csharp
+class CarImporter
+{
+    private int carsImported;
+
+    public void ImportCars(int numberOfCars)
+    {
+        // Update private field from public method
+        carsImported = carsImported + numberOfCars;
+    }
+}
+```
diff --git a/concepts/compound-assignment/introduction.md b/concepts/compound-assignment/introduction.md
new file mode 100644
index 0000000000..2fee3d9ef0
--- /dev/null
+++ b/concepts/compound-assignment/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for compound-assignment concept
diff --git a/concepts/const-readonly/introduction.md b/concepts/const-readonly/introduction.md
new file mode 100644
index 0000000000..940fa714dc
--- /dev/null
+++ b/concepts/const-readonly/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for const-readonly concept
diff --git a/concepts/constants/introduction.md b/concepts/constants/introduction.md
new file mode 100644
index 0000000000..9012326167
--- /dev/null
+++ b/concepts/constants/introduction.md
@@ -0,0 +1,18 @@
+The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
+
+```csharp
+private const int num = 1729;
+public const string title = "Grand" + " Master";
+```
+
+The `readonly` modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor).
+
+```csharp
+private readonly int num;
+private readonly System.Random rand = new System.Random();
+
+public MyClass(int num)
+{
+    this.num = num;
+}
+```
diff --git a/concepts/constructors/introduction.md b/concepts/constructors/introduction.md
new file mode 100644
index 0000000000..1fbd17c9ef
--- /dev/null
+++ b/concepts/constructors/introduction.md
@@ -0,0 +1,36 @@
+Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name.
+
+```csharp
+class Library
+{
+    private books;
+
+    public Library()
+    {
+        // Initialize the books field
+        this.books = 10;
+    }
+}
+
+// This will call the constructor
+var library = new Library();
+```
+
+Like regular methods, constructors can have parameters. Constructor parameters are usually stored as (private) fields to be accessed later, or else used in some one-off calculation. Arguments can be passed to constructors just like passing arguments to regular methods.
+
+```csharp
+class Building
+{
+    private int numberOfStories;
+    private int totalHeight;
+
+    public Building(int numberOfStories, double storyHeight)
+    {
+        this.numberOfStories = numberOfStories;
+        this.totalHeight = numberOfStories * storyHeight;
+    }
+}
+
+// Call a constructor with two arguments
+var largeBuilding = new Building(55, 6.2)
+```
diff --git a/concepts/datetimes/introduction.md b/concepts/datetimes/introduction.md
new file mode 100644
index 0000000000..7ba7a7786f
--- /dev/null
+++ b/concepts/datetimes/introduction.md
@@ -0,0 +1,5 @@
+A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`.
+
+The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`.
+
+Understanding which `DateTime` methods are culture-dependent is important to know. In general, any `DateTime` method that deals with `string`s (either as input or output) will be dependent on the current culture.
diff --git a/concepts/defensive-copying/introduction.md b/concepts/defensive-copying/introduction.md
new file mode 100644
index 0000000000..f920e8fda7
--- /dev/null
+++ b/concepts/defensive-copying/introduction.md
@@ -0,0 +1 @@
+In security sensitive situations (or even simply on a large code-base where developers have different priorities and agendas) you should avoid allowing a class's public API to be circumvented by accepting and storing a method's mutable parameters or by exposing a mutable member of a class through a return value or as an `out` parameter.
diff --git a/concepts/dictionaries/introduction.md b/concepts/dictionaries/introduction.md
new file mode 100644
index 0000000000..91a2a23020
--- /dev/null
+++ b/concepts/dictionaries/introduction.md
@@ -0,0 +1,60 @@
+A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages.
+
+A dictionary can be created as follows:
+
+```csharp
+new Dictionary();
+// Empty dictionary
+```
+
+Or
+
+```csharp
+new Dictionary
+{
+    [1] = "One",
+    [2] = "Two"
+};
+
+// Or
+
+new Dictionary
+{
+    {1, "One"},
+    {2, "Two"}
+};
+// 1 => "One", 2 => "Two"
+```
+
+Note that the key and value types are part of the definition of the dictionary.
+
+Once constructed, entries can be added or removed from a dictionary using its built-in methods `Add` and `Remove`.
+
+Retrieving or updating values in a dictionary is done by indexing into the dictionary using a key:
+
+```csharp
+var numbers = new Dictionary
+{
+   {1, "One"},
+   {2, "Two"}
+};
+
+// Set the value of the element with key 2 to "Deux"
+numbers[2] = "Deux";
+
+// Get the value of the element with key 2
+numbers[2];
+// => "Deux"
+```
+
+You can test if a value exists in the dictionary with:
+
+```csharp
+var dict = new Dictionary{/*...*/};
+dict.ContainsKey("some key that exists");
+// => true
+```
+
+Enumerating over a dictionary will enumerate over its key/value pairs. Dictionaries also have properties that allow enumerating over its keys or values.
+
+[indexer-properties]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/indexers/
diff --git a/concepts/do-while-loops/introduction.md b/concepts/do-while-loops/introduction.md
new file mode 100644
index 0000000000..87655882d1
--- /dev/null
+++ b/concepts/do-while-loops/introduction.md
@@ -0,0 +1,11 @@
+An less commonly used alternative to the above syntax is a `do-while` loop:
+
+```csharp
+int x = 23;
+
+do
+{
+    // Execute logic if x > 10
+    x = x - 2;
+} while (x > 10)
+```
diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md
new file mode 100644
index 0000000000..9f383a26bb
--- /dev/null
+++ b/concepts/enums/introduction.md
@@ -0,0 +1,22 @@
+The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows:
+
+```csharp
+enum Season
+{
+    Spring,
+    Summer,
+    Autumn,
+    Winter
+}
+```
+
+If not defined explicitly, enum members will automatically get assigned incrementing integer values, with the first value being zero. It is also possible to assign values explicitly:
+
+```csharp
+enum Answer
+{
+    Maybe = 1,
+    Yes = 3,
+    No = 5
+}
+```
diff --git a/concepts/equality/introduction.md b/concepts/equality/introduction.md
new file mode 100644
index 0000000000..c43fde97d1
--- /dev/null
+++ b/concepts/equality/introduction.md
@@ -0,0 +1,19 @@
+Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`.
+
+Reference types (Instances of classes) are compared using the `Equals()` method inherited from `Object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `Object`'s implementation will suffice. If not, you need to override `object.Equals()`.
+
+If you know that all the instances of your class are created in one place, say characters in some game or simulation then reference equality is sufficient. However, it is likely that multiple instances of the same real-world entity will be created (from a database, by user input, via a web request). In this case values that uniquely identify the entity must be tested for equality. Therefore `Equals()` must be overridden and appropriate data members of your class are tested for equality.
+
+An overridden `Equals()` method will contain equality tests on members of simple types using `==` and reference types with recursive calls to `Equals()`.
+
+The `Object` class provides appropriate methods to compare two objects to detect if they are one and the same instance.
+
+### `Object.GetHashCode()`
+
+The `Object.GetHashCode()` method returns a hash code in the form of a 32 bit integer. The hash code is used by _dictionary_ and _set_ classes such as `Dictionary` and `HashSet`to store and retrieve objects in a performant manner.
+
+The relationship between hash code and equality is that if two objects are equal (`Equal()` returns true) then `GetHashCode()` for the two objects must return the same value. This does not apply in the reverse direction. It is not symmetrical. Just because two objects have the same hashcode they do not have to be equal. Picture a lookup function that first goes to a "bucket" based on the hash code and then picks out the particular item using the equality test.
+
+The HashCode library API documentation discusses the best way to generate a hash code
+
+The values used in the equality test must be stable while the hashed collection is in use. If you add an object to the collection with one set of values and then change those values the hash code will no longer point to the correct "bucket". In practice this means that the object should be immutable. Other approaches run the risk of creating gotchas for maintainers.
diff --git a/concepts/exception-filtering/introduction.md b/concepts/exception-filtering/introduction.md
new file mode 100644
index 0000000000..69e80eaa79
--- /dev/null
+++ b/concepts/exception-filtering/introduction.md
@@ -0,0 +1,17 @@
+`when` is the key word in filtering exceptions. It is placed after the catch
+statement and can take a boolean expression containing any values in scope at the time. If the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked.
+
+```csharp
+try
+{
+    // do stuff
+}
+catch (Exception ex) when (ex.Message != "")
+{
+    // output the message when it is not empty
+}
+catch (Exception ex)
+{
+    // show stack trace or something.
+}
+```
diff --git a/concepts/exceptions/introduction.md b/concepts/exceptions/introduction.md
new file mode 100644
index 0000000000..002ea03980
--- /dev/null
+++ b/concepts/exceptions/introduction.md
@@ -0,0 +1,46 @@
+Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes.
+
+In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown.
+
+To signal that there should be an error in a certain part of the code, a new exception object needs to be created and then thrown, using the `throw` keyword:
+
+```csharp
+using System;
+static int Square(int number)
+{
+    if (number >= 46341)
+    {
+        throw new ArgumentException($"Argument {number} cannot be higher than 46340 as its' square doesn't fit into int type.");
+    }
+    return number * number;
+}
+```
+
+When an exception gets thrown, the runtime has the task of finding a piece of code that is responsible for handling of that exception. If no appropriate handler is found, the runtime displays the unhandled exception message in addition to stopping the execution of the program.
+
+To create a handler for an exception, C# uses the try-catch statement, which consists of a `try` block and one or more `catch` clauses. The `try` block should contain and guard code that may result in the exception getting thrown. The `catch` clauses should contain code that handles the behavior of the program after the error has occurred. It is important to note that the order of exceptions matters after the `try` block, as when multiple exceptions are listed, the first matching `catch` clause is executed.
+
+```csharp
+try
+{
+   if (number == 42)
+   {
+       throw new ArgumentException("The number cannot be equal to 42.", "number");
+   }
+
+   if (number < 0)
+   {
+      throw new ArgumentOutOfRangeException("number", "The number cannot be negative.");
+   }
+
+    // Process number ...
+}
+catch (ArgumentOutOfRangeException e)
+{
+    Console.WriteLine($"Number is out of range: {e.Message}.");
+}
+catch (ArgumentException)
+{
+    Console.WriteLine("Invalid number.");
+}
+```
diff --git a/concepts/explicit-casts/introduction.md b/concepts/explicit-casts/introduction.md
new file mode 100644
index 0000000000..c2a17943d1
--- /dev/null
+++ b/concepts/explicit-casts/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for explicit-casts concept
diff --git a/concepts/expression-bodied-members/introduction.md b/concepts/expression-bodied-members/introduction.md
new file mode 100644
index 0000000000..d5a9a75e37
--- /dev/null
+++ b/concepts/expression-bodied-members/introduction.md
@@ -0,0 +1,9 @@
+Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements.
+
+Methods and read-only properties are amongst the members that can be defined with expression bodies.
+
+```csharp
+public int Times3(int input) => input * 3;
+
+public int Interesting => 1729;
+```
diff --git a/concepts/flag-enums/introduction.md b/concepts/flag-enums/introduction.md
new file mode 100644
index 0000000000..f704ad50b5
--- /dev/null
+++ b/concepts/flag-enums/introduction.md
@@ -0,0 +1,27 @@
+The C# [`enum` type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) represents a fixed set of named constants (an enumeration).
+
+Normally, one `enum` member can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the [`Flags` attribute](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0). A _flags_ enum's constants are interpreted as bitwise _flags_ and therefor indicates the enum supports the bitwise operators and additional features like the method `Enum.HasFlag()`.
+
+A flags enum can be defined as follows (using binary integer notation `0b`):
+
+```csharp
+[Flags]
+enum PhoneFeatures
+{
+    Call = 0b00000001,
+    Text = 0b00000010
+}
+```
+
+A `PhoneFeatures` instance which value is `0b00000011` has both its `Call` _and_ `Text` flags set.
+
+By default, the `int` type is used for enum member values. One can use a different integer type by specifying the type in the enum declaration:
+
+```csharp
+[Flags]
+enum PhoneFeatures : byte
+{
+    Call = 0b00000001,
+    Text = 0b00000010
+}
+```
diff --git a/concepts/floating-point-numbers/introduction.md b/concepts/floating-point-numbers/introduction.md
new file mode 100644
index 0000000000..75294a6e65
--- /dev/null
+++ b/concepts/floating-point-numbers/introduction.md
@@ -0,0 +1,11 @@
+A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.
+
+Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision.
+
+C# has three floating-point types:
+
+- `float`: 4 bytes (~6-9 digits precision). Written as `2.45f`.
+- `double`: 8 bytes (~15-17 digits precision). This is the most common type. Written as `2.45` or `2.45d`.
+- `decimal`: 16 bytes (28-29 digits precision). Normally used when working with monetary data, as its precision leads to less rounding errors. Written as `2.45m`.
+
+As can be seen, each type can store a different number of digits. This means that trying to store PI in a `float` will only store the first 6 to 9 digits (with the last digit being rounded).
diff --git a/concepts/for-loops/introduction.md b/concepts/for-loops/introduction.md
new file mode 100644
index 0000000000..7e35bb6739
--- /dev/null
+++ b/concepts/for-loops/introduction.md
@@ -0,0 +1,13 @@
+If you want more control over which values to iterate over, a `for` loop can be used:
+
+```csharp
+char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' };
+
+for (int i = 0; i < 3; i++)
+{
+    // Output the vowel
+    System.Console.Write(vowels[i]);
+}
+
+// => aei
+```
diff --git a/concepts/foreach-loops/introduction.md b/concepts/foreach-loops/introduction.md
new file mode 100644
index 0000000000..694b15c182
--- /dev/null
+++ b/concepts/foreach-loops/introduction.md
@@ -0,0 +1,13 @@
+The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over _all_ its values using a `foreach` loop:
+
+```csharp
+char[] vowels = new [] { 'a', 'e', 'i', 'o', 'u' };
+
+foreach (char vowel in vowels)
+{
+    // Output the vowel
+    System.Console.Write(vowel);
+}
+
+// => aeiou
+```
diff --git a/concepts/generic-types/introduction.md b/concepts/generic-types/introduction.md
new file mode 100644
index 0000000000..19803e6658
--- /dev/null
+++ b/concepts/generic-types/introduction.md
@@ -0,0 +1 @@
+A collection definition typically includes a place holder in angle brackets, often `T` by convention. Such a collection is referred to as a generic type. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings.
diff --git a/concepts/if-statements/introduction.md b/concepts/if-statements/introduction.md
new file mode 100644
index 0000000000..640e904c2d
--- /dev/null
+++ b/concepts/if-statements/introduction.md
@@ -0,0 +1,20 @@
+In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement:
+
+```csharp
+int x = 6;
+
+if (x == 5)
+{
+    // Execute logic if x equals 5
+}
+else if (x > 7)
+{
+    // Execute logic if x greater than 7
+}
+else
+{
+    // Execute logic in all other cases
+}
+```
+
+The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values.
diff --git a/concepts/indexers/introduction.md b/concepts/indexers/introduction.md
new file mode 100644
index 0000000000..b3c1d000de
--- /dev/null
+++ b/concepts/indexers/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for indexers concept
diff --git a/concepts/inheritance/introduction.md b/concepts/inheritance/introduction.md
new file mode 100644
index 0000000000..32a4f8d3b0
--- /dev/null
+++ b/concepts/inheritance/introduction.md
@@ -0,0 +1,102 @@
+In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class.
+
+Parent classes can provide functionality to derived classes in three ways:
+
+- Define a regular method.
+- Define a `virtual` method, which is like a regular method but one that derived classes _can_ change.
+- Define an `abstract` method, which is a method without an implementation that derived classes _must_ implement. A class with `abstract` methods must be marked as `abstract` too. Abstract classes cannot be instantiated.
+
+The `protected` access modifier allows a parent class member to be accessed in a derived class, but blocks access from other classes.
+
+Derived classes can access parent class members through the `base` keyword.
+
+```csharp
+// Inherits from the 'object' class
+abstract class Vehicle
+{
+    // Can be overridden
+    public virtual void Drive()
+    {
+    }
+
+    // Must be overridden
+    protected abstract int Speed();
+}
+
+class Car : Vehicle
+{
+    public override void Drive()
+    {
+        // Override virtual method
+
+        // Call parent implementation
+        base.Drive();
+    }
+
+    protected override int Speed()
+    {
+        // Implement abstract method
+    }
+}
+```
+
+The constructor of a derived class will automatically call its parent's constructor _before_ executing its own constructor's logic. Arguments can be passed to a parent class' constructor using the `base` keyword:
+
+```csharp
+abstract class Vehicle
+{
+    protected Vehicle(int wheels)
+    {
+        Console.WriteLine("Called first");
+    }
+}
+
+class Car : Vehicle
+{
+    public Car() : base(4)
+    {
+        Console.WriteLine("Called second");
+    }
+}
+```
+
+Where more than one class is derived from a base class the two (or more) classes will often implement different versions of a base class method. This is a very important principle called polymorphism. For instance in a variation on the above example we show how code using `Vehicle` can change its behavior depending on what type of vehicle has been instantiated.
+
+```csharp
+abstract class Vehicle
+{
+   public abstract string GetDescription();
+}
+
+class Car : Vehicle
+{
+   public Car()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Runabout";
+   }
+}
+
+class Rig : Vehicle
+{
+   public Rig()
+   {
+   }
+
+   public override string GetDescription()
+   {
+      return "Big Rig";
+   }
+}
+
+Vehicle v1 = new Car();
+Vehicle v2 = new Rig();
+
+v1.GetDescription();
+// => Runabout
+v2.GetDescription();
+// => Big Rig
+```
diff --git a/concepts/integral-numbers/introduction.md b/concepts/integral-numbers/introduction.md
new file mode 100644
index 0000000000..a134fd0930
--- /dev/null
+++ b/concepts/integral-numbers/introduction.md
@@ -0,0 +1,34 @@
+C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types.
+
+The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits.
+
+Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1.
+
+| Type   | Width  | Minimum                    | Maximum                     |
+| ------ | ------ | -------------------------- | --------------------------- |
+| sbyte  | 8 bit  | -128                       | +127                        |
+| short  | 16 bit | -32_768                    | +32_767                     |
+| int    | 32 bit | -2_147_483_648             | +2_147_483_647              |
+| long   | 64 bit | -9_223_372_036_854_775_808 | +9_223_372_036_854_775_807  |
+| byte   | 8 bit  | 0                          | +255                        |
+| ushort | 16 bit | 0                          | +65_535                     |
+| uint   | 32 bit | 0                          | +4_294_967_295              |
+| ulong  | 64 bit | 0                          | +18_446_744_073_709_551_615 |
+
+A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (lhs) ensures that the value will lie within the range of the type being assigned to (rhs) then there is a simple assignment:
+
+```csharp
+uint ui = uint.MaxValue;
+ulong ul = ui;    // no problem
+```
+
+On the other hand if the range of type being assigned from is not a subset of the assignee's range of values then a cast, `()` operation is required even if the particular value is within the assignee's range:
+
+```csharp
+short s = 42;
+uint ui = (uint)s;
+```
+
+#### Bit conversion
+
+The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes.
diff --git a/concepts/interfaces/introduction.md b/concepts/interfaces/introduction.md
new file mode 100644
index 0000000000..1bfe42581d
--- /dev/null
+++ b/concepts/interfaces/introduction.md
@@ -0,0 +1,32 @@
+An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion.
+
+The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided.
+
+```csharp
+public interface ILanguage
+{
+    string LanguageName { get; set; }
+    string Speak();
+}
+
+public class ItalianTaveller : ILanguage, ICloneable
+{
+    public string LanguageName { get; set; } =  "Italiano";
+
+    public string Speak()
+    {
+        return "Ciao mondo";
+    }
+
+    public object Clone()
+    {
+        ItalianTaveller it = new ItalianTaveller();
+        it.LanguageName = this.LanguageName;
+        return it;
+    }
+}
+```
+
+All operations defined by the interface must be implemented.
+
+Interfaces can contain instance methods and properties amongst other members
diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md
new file mode 100644
index 0000000000..a4cbeb6b64
--- /dev/null
+++ b/concepts/lists/introduction.md
@@ -0,0 +1,7 @@
+Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists.
+
+Items can be added to and removed from lists. They grow and shrink as necessary.
+
+```csharp
+var listOfStrings = new List();
+```
diff --git a/concepts/memory-allocation/introduction.md b/concepts/memory-allocation/introduction.md
new file mode 100644
index 0000000000..7f76d1971a
--- /dev/null
+++ b/concepts/memory-allocation/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for memory-allocation concept
diff --git a/concepts/method-overloading/introduction.md b/concepts/method-overloading/introduction.md
new file mode 100644
index 0000000000..419e231fe4
--- /dev/null
+++ b/concepts/method-overloading/introduction.md
@@ -0,0 +1,8 @@
+_Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
+
+- The number of parameters
+- The type of the parameters
+
+There is no method overloading based on the return type.
+
+The compiler will automatically infer which overloaded method to call based on the number of parameters and their type.
diff --git a/concepts/named-arguments/introduction.md b/concepts/named-arguments/introduction.md
new file mode 100644
index 0000000000..24bdcdb12d
--- /dev/null
+++ b/concepts/named-arguments/introduction.md
@@ -0,0 +1,15 @@
+So far we have seen that the arguments passed into a method are matched to the method are matched to the method's declared parameters based on position. An alternative approach, particularly where a routine takes a large number of arguments, the caller can match arguments by specifying the declared parameter's identifier.
+
+The following illustrates the syntax:
+
+```csharp
+class Card
+{
+    static string NewYear(int year, int month, int day)
+    {
+        return $"Happy {year}-{month}-{day}!";
+    }
+}
+
+Card.NewYear(month: 1, day: 1, year: 2020);  // => "Happy 2020-1-1!"
+```
diff --git a/concepts/namespaces/introduction.md b/concepts/namespaces/introduction.md
new file mode 100644
index 0000000000..ccfd49113a
--- /dev/null
+++ b/concepts/namespaces/introduction.md
@@ -0,0 +1,52 @@
+Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base.
+
+The syntax is as follows:
+
+```csharp
+namespace MyNameSpace
+{
+    public class MyClass {}
+
+    public class OtherClass {}
+}
+```
+
+Types enclosed in namespaces are referred to outside the scope of the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and type can be used without the prefix. Within the same namespace there is no need to qualify type names.
+
+```csharp
+namespace MySpace
+{
+    public class MyClass {}
+
+    public class Foo
+    {
+        public void Bar()
+        {
+            var baz = new MyClass();
+        }
+    }
+}
+
+public class Qux
+{
+    public void Box()
+    {
+        var nux = new MySpace.MyClass();
+    }
+}
+
+namespace OtherSpace
+{
+    using MySpace;
+
+    public class Tix
+    {
+        public void Jeg()
+        {
+            var lor = new MyClass();
+        }
+    }
+}
+```
+
+You can alias a namespace with the syntax `using MyAlias = MySpace;` and then use the alias anywhere that the namespace could be used.
diff --git a/concepts/nested-types/introduction.md b/concepts/nested-types/introduction.md
new file mode 100644
index 0000000000..1edafdd14b
--- /dev/null
+++ b/concepts/nested-types/introduction.md
@@ -0,0 +1,18 @@
+C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax.
+
+```csharp
+class Outer
+{
+    public interface IInner {}
+    public enum EInner {}
+    public class CInner {}
+    public struct SInner {}
+}
+
+var outer = new Outer();
+var inner = new Outer.CInner();
+```
+
+You can set access levels for inner types.
+
+Private members of the outer type are in scope for members of the inner type but not vice versa.
diff --git a/concepts/nullability/introduction.md b/concepts/nullability/introduction.md
new file mode 100644
index 0000000000..6ce9868e2e
--- /dev/null
+++ b/concepts/nullability/introduction.md
@@ -0,0 +1,76 @@
+In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values.
+
+Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`).
+
+```csharp
+string nullableReferenceType = "hello";
+nullableReferenceType = null; // Valid as type is nullable
+
+int nonNullableValueType = 5;
+nonNullableValueType = null; // Compile error as type is not nullable
+
+int? nullableValueType = 5; // Define nullable value type
+nullableValueType = null;   // Valid as type is nullable
+```
+
+Accessing a member of a variable which value is `null` will compile fine, but result in a `NullReferenceException` being thrown at runtime:
+
+```csharp
+string sentence = null;
+
+// Throws NullReferenceException at runtime
+sentence.Length;
+```
+
+To counter this common type of mistake, C# 8 allows one to opt-into a feature that makes reference types non-nullable by default:
+
+```csharp
+string nonNullableReferenceType = "book";
+nonNullableReferenceType = null; // Compile warning (no error!)
+
+string? nullableReferenceType = "movie";
+nullableReferenceType = null; // Valid as type is nullable
+```
+
+To safely work with nullable values, one should check if they are `null` before working with them:
+
+```csharp
+string NormalizedName(string? name)
+{
+    if (name == null)
+    {
+        return "UNKNOWN";
+    }
+    else
+    {
+        // Value is not null at this point, so no compile warning
+        // and no runtime NullReferenceException being thrown
+        return name.ToUpper();
+    }
+}
+
+NormalizedName(null); // => "UNKNOWN"
+NormalizedName("Elisabeth"); // => "ELISABETH"
+```
+
+The `??` operator allows one to return a default value when the value is `null`:
+
+```csharp
+string? name1 = "John";
+name1 ?? "Paul"; // => "John"
+
+string? name2 = null;
+name2 ?? "George"; // => "George"
+```
+
+The `?.` operator allows one to call members safely on a possibly `null` value:
+
+```csharp
+string? fruit = "apple";
+fruit?.Length; // => 5
+
+string? vegetable = null;
+vegetable?.Length; // => null
+```
+
+[nullable-csharp-8]: https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references
diff --git a/concepts/numbers/introduction.md b/concepts/numbers/introduction.md
new file mode 100644
index 0000000000..52f5a0bd54
--- /dev/null
+++ b/concepts/numbers/introduction.md
@@ -0,0 +1,15 @@
+There are two different types of numbers in C#:
+
+- Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`.
+- Floating-point numbers: numbers with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.
+
+The two most common numeric types in C# are `int` and `double`. An `int` is a 32-bit integer and a `double` is a 64-bit floating-point number.
+
+Arithmetic is done using the standard arithmetic operators. Numbers can be compared using the standard numeric comparison operators and the equality (`==`) and inequality (`!=`) operators.
+
+C# has two types of numeric conversions:
+
+1. Implicit conversions: no data will be lost and no additional syntax is required.
+2. Explicit conversions: data could be lost and additional syntax in the form of a _cast_ is required.
+
+As an `int` has less precision than a `double`, converting from an `int` to a `double` is safe and is thus an implicit conversion. However, converting from a `double` to an `int` could mean losing data, so that requires an explicit conversion.
diff --git a/concepts/object-initializers/introduction.md b/concepts/object-initializers/introduction.md
new file mode 100644
index 0000000000..25b3b07ef5
--- /dev/null
+++ b/concepts/object-initializers/introduction.md
@@ -0,0 +1,27 @@
+Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets:
+
+```csharp
+public class Person
+{
+    public string Name;
+    public string Address;
+}
+
+var person = new Person{Name="The President", Address = "Élysée Palace"};
+```
+
+Collections can also be initialized in this way. Typically, this is accomplished with comma separated lists as shown here:
+
+```csharp
+IList people = new List{ new Person(), new Person{Name="Joe Shmo"}};
+```
+
+Dictinaries use the following syntax:
+
+```csharp
+IDictionary numbers = new Dictionary{ [0] = "zero", [1] = "one"...};
+
+// or
+
+IDictionary numbers = new Dictionary{ {0, "zero" }, {1,  "one"}...};
+```
diff --git a/concepts/operator-overloading/introduction.md b/concepts/operator-overloading/introduction.md
new file mode 100644
index 0000000000..9c72dea800
--- /dev/null
+++ b/concepts/operator-overloading/introduction.md
@@ -0,0 +1,15 @@
+The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_.
+
+Most operators have the form:
+
+```csharp
+static  operator ();
+```
+
+Cast operators have the form:
+
+```csharp
+static (explicit|implicit) operator ( );
+```
+
+Operators behave in the same way as static methods. An operator symbol takes the place of a method identifier, and they have parameters and a return type. The type rules for parameters and return type follow your intuition and you can rely on the compiler to provide detailed guidance.
diff --git a/concepts/optional-parameters/introduction.md b/concepts/optional-parameters/introduction.md
new file mode 100644
index 0000000000..5a8afa0d25
--- /dev/null
+++ b/concepts/optional-parameters/introduction.md
@@ -0,0 +1,16 @@
+A method parameter can be made optional by assigning it a default value. When calling a method with optional parameters, the caller is not required to pass a value for them. If no value is passed for an optional parameter, its default value will be used.
+
+Optional parameters _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters.
+
+```csharp
+class Card
+{
+    static string NewYear(int year = 2020)
+    {
+        return $"Happy {year}!";
+    }
+}
+
+Card.NewYear();  // => "Happy 2020!"
+Card.Card(1999); // => "Happy 1999!"
+```
diff --git a/concepts/ordering/introduction.md b/concepts/ordering/introduction.md
new file mode 100644
index 0000000000..9f877ecd2a
--- /dev/null
+++ b/concepts/ordering/introduction.md
@@ -0,0 +1 @@
+The `IComparable` interface can be implemented where a default generic sort order in collections is required.
diff --git a/concepts/overflow/introduction.md b/concepts/overflow/introduction.md
new file mode 100644
index 0000000000..a2313bf95e
--- /dev/null
+++ b/concepts/overflow/introduction.md
@@ -0,0 +1,21 @@
+Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type.
+
+Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances.
+
+The behavior of integer computations can be modified by using the `checked` keyword. When an overflow occurs within a `checked` block an instance of `OverflowException` is thrown.
+
+```csharp
+int one = 1;
+checked
+{
+    int expr = int.MaxValue + one;   // OverflowException is thrown
+}
+
+// or
+
+int expr2 = checked(int.MaxValue + one);     // OverflowException is thrown
+```
+
+Expressions of type `float` and `double` will take a special value of infinity.
+
+Expressions of type `decimal` will throw an instance of `OverflowException`.
diff --git a/concepts/parameters/introduction.md b/concepts/parameters/introduction.md
new file mode 100644
index 0000000000..1c42283f86
--- /dev/null
+++ b/concepts/parameters/introduction.md
@@ -0,0 +1,47 @@
+This exercise discusses some details of method parameters and their use in C#.
+
+Parameters convey information from a calling method to a called method.
+
+- The behavior of parameters can be modified by the use of modifies such as `ref` and `out`.
+
+- A parameter with the `out` modifier conveys a value back from the called method to the caller. The parameter can be passed to the called method without being initialized and in any case it is treated within the called method as if, on entry, it had not been initialized. An understanding of the behavior and rules regarding parameter modifiers can be gained most easily through examples (see below) and compiler messages.
+
+```csharp
+void Foo(out int val)
+{
+    val = 42;
+}
+void Bar(int val)
+{
+    val = 42;
+}
+
+int importantValue = 1729;
+Foo(out importantValue);
+var result = importantValue == 42;
+// => true
+
+importantValue = 1729;
+Bar(importantValue);
+result = importantValue == 1729;
+// => true
+```
+
+- `out` parameters must be assigned to within a called method.
+
+- A parameter with the `ref` modifier passes a value into a called method. When the method returns the caller will find any updates made by the called method in that parameter.
+
+```csharp
+void Foo(ref int val)
+{
+    val *= 7;
+}
+
+int importantValue = 6;
+Foo(ref importantValue);
+return importantValue;
+// => 42
+```
+
+- `ref` parameters must be variables as the called method will be operating directly on the parameter as seen by the caller.
+- The `out` and `ref` modifiers are required both in the called method signature and at the call site.
diff --git a/concepts/properties/introduction.md b/concepts/properties/introduction.md
new file mode 100644
index 0000000000..1405dddcca
--- /dev/null
+++ b/concepts/properties/introduction.md
@@ -0,0 +1,38 @@
+A property in C# is a member of a class that provides access to data within that class.
+Callers can set or retrieve (get) the data. Properties can be either auto-implemented or
+have a backing field. They comprise a set accessor and/or a get accessor.
+In some other languages a "mutator" is roughly equivalent to a
+a set accessor and an "accessor" is roughly equivalent to a set accessor although
+the composition of the syntax is completely different.
+
+When setting a property the input value can be validated, formatted
+or otherwise manipulated and in fact any programmatic operation accessible to code in the
+class can be executed.
+
+Similarly when retrieving a property data can be calculated or formatted and again
+any programmatic operation available to the class can be executed.
+
+Properties have access modifiers (`public`, `private` etc.) in the same way as other
+class members but the set accessor may have an access level independent of the retrieve (get)
+accessor and vice versa. A property doesn't have to have both accessors, it can have just one (either get or set).
+
+The basic syntax to express properties can take two forms:
+
+#### Field/Expression Backed Properties:
+
+```csharp
+private int myField;
+public int MyProperty
+{
+    get { return myfField; }
+    set { myField = value; }
+}
+```
+
+#### Auto-implemented Properties
+
+```
+public int MyProperty { get; private set; } = 42;
+```
+
+Initialization is optional.
diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md
new file mode 100644
index 0000000000..264aec91ec
--- /dev/null
+++ b/concepts/randomness/introduction.md
@@ -0,0 +1 @@
+In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case.
diff --git a/concepts/readonly-collections/introduction.md b/concepts/readonly-collections/introduction.md
new file mode 100644
index 0000000000..4b42299301
--- /dev/null
+++ b/concepts/readonly-collections/introduction.md
@@ -0,0 +1,18 @@
+While the `readonly` modifier prevents the value or reference in a field from being overwritten, it offers no protection for the members of a reference type.
+
+```csharp
+readonly List ints = new List();
+
+void Foo()
+{
+    ints.Add(1);    // ok
+    ints = new List(); // fails to compile
+}
+```
+
+To ensure that all members of a reference type are protected the fields can be made `readonly` and automatic properties can be defined without a `set` accessor.
+
+The Base Class Library (BCL) provides some readonly versions of collections where there is a requirement to stop members of a collections being updated. These come in the form of wrappers:
+
+- `ReadOnlyDictionary` exposes a `Dictionary` as read-only.
+- `ReadOnlyCollection` exposes a `List` as read-only.
diff --git a/concepts/regular-expressions/introduction.md b/concepts/regular-expressions/introduction.md
new file mode 100644
index 0000000000..1256179199
--- /dev/null
+++ b/concepts/regular-expressions/introduction.md
@@ -0,0 +1 @@
+The .NET base class libraries provide the `Regex` class for processing of regular expressions.
diff --git a/concepts/resource-cleanup/introduction.md b/concepts/resource-cleanup/introduction.md
new file mode 100644
index 0000000000..ffeafbf696
--- /dev/null
+++ b/concepts/resource-cleanup/introduction.md
@@ -0,0 +1 @@
+If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset.
diff --git a/concepts/resource-lifetime/introduction.md b/concepts/resource-lifetime/introduction.md
new file mode 100644
index 0000000000..ee0bef510d
--- /dev/null
+++ b/concepts/resource-lifetime/introduction.md
@@ -0,0 +1,30 @@
+You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations.
+
+There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement.
+
+```csharp
+using (var file = new File("my_secrets"))
+{
+    file.WriteSecret("xxxxxxx");
+}
+```
+
+In the above example the file system resources associated with `file` will be released back to the operating system when the `using` block is exited.
+
+For the pattern to work the variable in the using statement must be a reference type that implements the `IDisposable` interface and must release resources/reset program state in its `Dispose()` method.
+
+C# 8 introduces a refinement to the pattern. A using statement can placed at the beginning of a block.
+
+```csharp
+using var drawingResource = some_provided_or_new_object;
+try
+{
+    drawingResource.DrawSomething();
+}
+catch (Exception)
+{
+    throw;
+}
+```
+
+Java developers may recognize this as an analog of the _automatic resource management_ mechanism introduced in Java 7.
diff --git a/concepts/sets/introduction.md b/concepts/sets/introduction.md
new file mode 100644
index 0000000000..8ffeab96e7
--- /dev/null
+++ b/concepts/sets/introduction.md
@@ -0,0 +1 @@
+The `HashSet` library class provides a good mechanism for storing unique values.
diff --git a/concepts/string-builder/introduction.md b/concepts/string-builder/introduction.md
new file mode 100644
index 0000000000..e422be5590
--- /dev/null
+++ b/concepts/string-builder/introduction.md
@@ -0,0 +1,4 @@
+`char`s are sometimes used in conjunction with a `StringBuilder` object.
+This object has methods that allow a string to be constructed
+character by character and manipulated. At the end of the process
+`ToString` can be called on it to output a complete string.
diff --git a/concepts/string-formatting/introduction.md b/concepts/string-formatting/introduction.md
new file mode 100644
index 0000000000..10e8993bd9
--- /dev/null
+++ b/concepts/string-formatting/introduction.md
@@ -0,0 +1,57 @@
+There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation.
+
+### Composite Formatting
+
+`String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as format items), and a variable number of arguments. The return value resolves each format item using the corresponding argument and combines the resolved values with the fixed text.
+
+```csharp
+string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5, new DateTime(2010, 2, 25));
+// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
+```
+
+This mechanism is technically known as _composite formatting_.
+
+### String Interpolation
+
+Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism.
+
+```csharp
+var loadsOf = 55.5;
+var thatDay = new DateTime(2010, 2, 25);
+$"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
+// => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
+```
+
+### Format Items
+
+The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_.
+
+A format item can comprise up to 3 parts. The first is the mandatory expression or argument placeholder as seen in the example code above. In addition, there is an optional alignment (introduced with a comma, ",") and an optional _format string_ (introduced with a colon ":").
+
+`{[,][:]`
+
+The _alignment_ specifies the length of the "field" in which the text is placed, padded to the left with spaces if the alignment is negative or to the right if it is positive.
+
+The _format string_ specifies the shape of the text output such as whether thousands separators should be included for a number or whether the date part only of a `DateTime` object should be output.
+
+The following code illustrates display of the data portion of a `DateTime` object and a floating-point number in exponential form.
+
+```csharp
+var loadsOf = 55.5;
+var thatDay = new DateTime(2010, 2, 25);
+$"I had {loadsOf:E} bitcoins on {thatDay:d}, the day I forgot my password."
+// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
+
+string.Format(
+    "I had {0:E} bitcoins on {1:d}, the day I forgot my password.",
+    loadsOf, thatDay)
+// => I had 5.550000E+001 bitcoins on 02/25/2010, the day I forgot my password. - US settings
+```
+
+There are both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format letters.
+
+### Culture
+
+Each thread has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_.
+
+`CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture.
diff --git a/concepts/string-interpolation/introduction.md b/concepts/string-interpolation/introduction.md
new file mode 100644
index 0000000000..8363fc87b6
--- /dev/null
+++ b/concepts/string-interpolation/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for string-interpolation concept
diff --git a/concepts/strings/introduction.md b/concepts/strings/introduction.md
new file mode 100644
index 0000000000..d7d72cd2ec
--- /dev/null
+++ b/concepts/strings/introduction.md
@@ -0,0 +1,23 @@
+A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance:
+
+```csharp
+string fruit = "Apple";
+```
+
+Strings are manipulated by calling the string's methods. Once a string has been constructed, its value can never change. Any methods that appear to modify a string will actually return a new string.
+
+Multiple strings can be concatenated (added) together. The simplest way to achieve this is by using the `+` operator.
+
+```csharp
+string name = "Jane";
+"Hello " + name + "!";
+// => "Hello Jane!"
+```
+
+For any string formatting more complex than simple concatenation, string interpolation is preferred. To use interpolation in a string, prefix it with the dollar (`$`) symbol. Then you can use curly braces (`{}`) to access any variables inside your string.
+
+```csharp
+string name = "Jane";
+$"Hello {name}!";
+// => "Hello Jane!"
+```
diff --git a/concepts/structs/introduction.md b/concepts/structs/introduction.md
new file mode 100644
index 0000000000..6b1142d00f
--- /dev/null
+++ b/concepts/structs/introduction.md
@@ -0,0 +1,28 @@
+C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.
+
+```csharp
+enum Unit
+{
+    Kg,
+    Lb
+}
+struct Weight
+{
+    private double count;
+    private Unit unit;
+
+    public Weight(double count, Unit unit)
+    {
+        this.count = count;
+        this.unit = unit;
+    }
+
+    public override string ToString()
+    {
+        return count.ToString() + unit.ToString();
+    }
+}
+
+new Weight(77.5, Unit.Kg).ToString();
+// => "77.6Kg"
+```
diff --git a/concepts/switch-expressions/introduction.md b/concepts/switch-expressions/introduction.md
new file mode 100644
index 0000000000..e8a499e31d
--- /dev/null
+++ b/concepts/switch-expressions/introduction.md
@@ -0,0 +1,17 @@
+A switch expression can match a value to one case in a set of patterns and return the associated value or take the associated action. The association is denoted by the `=>` symbol. In addition, each pattern can have an optional case guard introduced with the `when` keyword. The case guard expression must evaluate to true for that "arm" of the switch to be selected. The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found.
+
+```csharp
+double xx = 42d;
+
+string interesting = xx switch
+{
+    0 => "I suppose zero is interesting",
+    3.14 when DateTime.Now.Day == 14 && DateTime.Now.Month == 3 => "Mmm pie!",
+    3.14 => "π",
+    42 => "a bit of a cliché",
+    1729 => "only if you are a pure mathematician",
+    _ => "not interesting"
+};
+
+// => interesting == "a bit of a cliché"
+```
diff --git a/concepts/switch-statements/introduction.md b/concepts/switch-statements/introduction.md
new file mode 100644
index 0000000000..8395a6f1c9
--- /dev/null
+++ b/concepts/switch-statements/introduction.md
@@ -0,0 +1,42 @@
+Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program".
+
+The mechanism involves the following keywords: `switch`, `case`, `break` and `default`.
+
+At their simplest they test a primitive or string expression and make a decision based on its value. For example:
+
+```csharp
+string direction = GetDirection();
+switch (direction)
+{
+    case "left":
+        GoLeft();
+        break;
+    case "right":
+        GoRight();
+        break;
+    default:
+        MarkTime();
+        break;
+}
+```
+
+At their most sophisticated they introduce down casting `case  :` and guards (`when`).
+
+```csharp
+Animal animal = GetAnimal();
+
+switch (animal)
+{
+    case Dog canine:
+    case Coyote canine:
+        canine.Bark();
+        break;
+    case Cat cat when cat.HasOnly8Lives():
+        cat.IsCareful();
+        cat.Meow();
+        break;
+    case Cat cat:
+        cat.Meow();
+        break;
+}
+```
diff --git a/concepts/ternary-operators/introduction.md b/concepts/ternary-operators/introduction.md
new file mode 100644
index 0000000000..96c22f0dad
--- /dev/null
+++ b/concepts/ternary-operators/introduction.md
@@ -0,0 +1,9 @@
+Ternary operators allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone.
+
+The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`).
+
+```csharp
+int a = 3, b = 4;
+int max = a > b ? a : b;
+// => 4
+```
diff --git a/concepts/throw-expressions/introduction.md b/concepts/throw-expressions/introduction.md
new file mode 100644
index 0000000000..0f6488613a
--- /dev/null
+++ b/concepts/throw-expressions/introduction.md
@@ -0,0 +1,5 @@
+`throw` expressions are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions.
+
+```csharp
+string trimmed = str == null ? throw new ArgumentException() : str.Trim();
+```
diff --git a/concepts/time/introduction.md b/concepts/time/introduction.md
new file mode 100644
index 0000000000..b6a66cfb7a
--- /dev/null
+++ b/concepts/time/introduction.md
@@ -0,0 +1 @@
+The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`.
diff --git a/concepts/timezone/introduction.md b/concepts/timezone/introduction.md
new file mode 100644
index 0000000000..1fc8e89c65
--- /dev/null
+++ b/concepts/timezone/introduction.md
@@ -0,0 +1,5 @@
+The `TimeZoneInfo` class provides routines for handling the differences between time zones. The `TimeZoneInfo` class also contains methods that facilitate dealing with daylight saving time.
+
+The `CultureInfo` class supports locale dependent date time formats.
+
+To support cross-platform coding the `RuntimeInformation` class allows you to detect which operating system your code is executing on, Linux, Windows or OSX.
diff --git a/concepts/tuples/introduction.md b/concepts/tuples/introduction.md
new file mode 100644
index 0000000000..88510ef0c5
--- /dev/null
+++ b/concepts/tuples/introduction.md
@@ -0,0 +1,51 @@
+In C#, a tuple is a data structure which organizes data, holding two or more fields
+of any type.
+
+A tuple is typically created by placing 2 or more expressions separated by comas,
+within a set of parentheses.
+
+```csharp
+string boast = "All you need to know";
+bool success = !string.IsNullOrWhiteSpace(boast);
+(bool, int, string) triple = (success, 42, boast);
+```
+
+A tuple can be used in assignment and initialization operations, as a return value or a method argument.
+
+Fields are extracted using dot syntax. By default, the first field is `Item1`,
+the second `Item2`, etc. Non-default names are discussed below.
+
+```csharp
+// initialization
+(int, int, int) vertices = (90, 45, 45);
+
+// assignment
+vertices = (60, 60, 60);
+
+//  return value
+(bool, int) GetSameOrBigger(int num1, int num2)
+{
+    return (num1 == num2, num1 > num2 ? num1 : num2);
+}
+
+// method argument
+int Add((int, int) operands)
+{
+    return operands.Item1 + operands.Item2;
+}
+```
+
+Field names `Item1` etc. do not make for readable code. The code below shows
+2 ways to name the fields of tuples. Note also, in the code below, that `var` can be used with tuples and the type inferred. This works equally well for tuples with named and unnamed fields.
+
+```csharp
+// name items in declaration
+(bool success, string message) results = (true, "well done!");
+bool mySuccess = results.success;
+string myMessage = results.message;
+
+// name items in creating expression
+var results2 = (success: true, message: "well done!");
+bool mySuccess2 = results2.success;
+string myMessage2 = results2.message;
+```
diff --git a/concepts/user-defined-exceptions/introduction.md b/concepts/user-defined-exceptions/introduction.md
new file mode 100644
index 0000000000..8c81022f15
--- /dev/null
+++ b/concepts/user-defined-exceptions/introduction.md
@@ -0,0 +1,3 @@
+A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise.
+
+User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines.
diff --git a/concepts/varargs/introduction.md b/concepts/varargs/introduction.md
new file mode 100644
index 0000000000..6398d1241c
--- /dev/null
+++ b/concepts/varargs/introduction.md
@@ -0,0 +1 @@
+TODO: add introduction for varargs concept
diff --git a/concepts/verbatim-strings/introduction.md b/concepts/verbatim-strings/introduction.md
new file mode 100644
index 0000000000..182dd64098
--- /dev/null
+++ b/concepts/verbatim-strings/introduction.md
@@ -0,0 +1,8 @@
+Verbatim strings allow multi-line strings. They are introduced with an @.
+
+```csharp
+string str = @"
+See no wretched
+quotes everywhere
+";
+```
diff --git a/concepts/while-loops/introduction.md b/concepts/while-loops/introduction.md
new file mode 100644
index 0000000000..7f7d278c6c
--- /dev/null
+++ b/concepts/while-loops/introduction.md
@@ -0,0 +1,11 @@
+In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here:
+
+```csharp
+int x = 23;
+
+while (x > 10)
+{
+    // Execute logic if x > 10
+    x = x - 2;
+}
+```

From 40d4ab2133d620862e48a1ee5badf102d26717d2 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Wed, 13 Jan 2021 16:38:20 +0100
Subject: [PATCH 293/327] Move custom docs to reference folder

---
 reference/docs/code_style.md        | 49 +++++++++++++++++++++++++++++
 reference/docs/memory_allocation.md | 28 +++++++++++++++++
 2 files changed, 77 insertions(+)
 create mode 100644 reference/docs/code_style.md
 create mode 100644 reference/docs/memory_allocation.md

diff --git a/reference/docs/code_style.md b/reference/docs/code_style.md
new file mode 100644
index 0000000000..59ad5be88d
--- /dev/null
+++ b/reference/docs/code_style.md
@@ -0,0 +1,49 @@
+# Code style
+
+While the C# compiler doesn't enforce a particular code style, there are general [coding conventions][docs.microsoft.com_coding-conventions] and [design guidelines][docs.microsoft.com_design-guidelines].
+
+## Formatting conventions
+
+The C# formatting formatting conventions are defined in the [layout conventions][docs.microsoft.com_layout-conventions].
+
+## Naming conventions
+
+Broadly speaking, the C# naming conventions are as follows:
+
+- PascalCase for types, methods and constants.
+- camelCase for fields, variables and parameters.
+
+These conventions are described in the [.NET capitalization conventions][docs.microsoft.com_capitalization-conventions] and the [.NET general naming conventions][docs.microsoft.com_general-naming-conventions].
+
+## Other conventions
+
+### Prefer type alias
+
+The general consensus is to prefer the C# type over the .NET type. Here are some examples where this prefererence shows:
+
+- The default [C# editorconfig settings][docs.microsoft.com_editorconfig-language-keywords].
+- The [ReSharper built-in type naming rule][jetbrains.com_built-in-type-naming].
+- The [CoreFX coding style document][github.com_corefx-coding-style].
+
+## Enforcing code style
+
+It is possible to encode C# coding style conventions using [`.editorconfig files`][docs.microsoft.com_editorconfig]. This includes being able to specify [formatting conventions][docs.microsoft.com_editorconfig-formatting-conventions] and [naming conventions][docs.microsoft.com_editorconfig-naming-conventions].
+
+Most C# IDE's have support for `.editorconfig` files, including Visual Studio 2019+, Rider and VS Code (using the C# extension).
+
+The [dotnet format global tool][github.com_dotnet-format-editorconfig-options] can be run as a [command-line tool][github.com_dotnet-format-how-to] and has support for a [limited set of the `.editorconfig` settings][github.com_dotnet-format-editorconfig-options].
+
+[docs.microsoft.com_design-guidelines]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/
+[docs.microsoft.com_coding-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions
+[docs.microsoft.com_capitalization-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/capitalization-conventions
+[docs.microsoft.com_general-naming-conventions]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions
+[docs.microsoft.com_layout-conventions]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions#layout-conventions
+[docs.microsoft.com_editorconfig]: https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2019
+[docs.microsoft.com_editorconfig-formatting-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-formatting-conventions?view=vs-2019
+[docs.microsoft.com_editorconfig-naming-conventions]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-naming-conventions?view=vs-2019
+[github.com_dotnet-format]: https://github.com/dotnet/format/blob/master/README.md
+[github.com_dotnet-format-editorconfig-options]: https://github.com/dotnet/format/wiki/Supported-.editorconfig-options
+[github.com_dotnet-format-how-to]: https://github.com/dotnet/format/blob/master/README.md#how-to-install
+[docs.microsoft.com_editorconfig-language-keywords]: https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-language-conventions?view=vs-2019#language-keywords
+[github.com_corefx-coding-style]: https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md
+[jetbrains.com_built-in-type-naming]: https://www.jetbrains.com/help/resharper/Built_In_Type_Naming.html
diff --git a/reference/docs/memory_allocation.md b/reference/docs/memory_allocation.md
new file mode 100644
index 0000000000..81e4fbe7f4
--- /dev/null
+++ b/reference/docs/memory_allocation.md
@@ -0,0 +1,28 @@
+# Memory allocation
+
+The important thing about allocating memory in C# is that it is done _automatically_; there is no need to manually allocate memory. To allow the automatic memory to also be deallocated when it is no longer used, C# uses a [garbage collector][docs.microsoft.com_garbage-collection-fundamentals].
+
+There are two different types of memory used when working with C#:
+
+- The stack.
+- The heap.
+
+The stack is short-lived and has limited space available. Exceeding the maximum amount of allowed memory of the stack results in a `StackOverflowException` being thrown. Each thread has its own stack. As the stack is automatically "unwinded" after a method returns, there is no need for the garbage collector to be involved. This means that (de)allocating memory on the stack is very fast.
+
+The heap is long-lived and has lots of memory available. When an object is allocated, the memory allocator will find some free memory on the heap and allocate it. The heap is shared between threads and can be used to share data. Once every while, the garbage collector will halt execution (a "GC pause") and check if there are objects that are no longer being used. If so, the memory for these objects will be deallocated and their memory will become available for later allocation again.
+
+## What goes where?
+
+In principle, value types are allocated on the stack and reference types on the heap. There are some exceptions to this, for example when a value type is part of a reference type (e.g. a class with an `int` field).
+
+## Resources
+
+- [Garbage collection fundamentals][docs.microsoft.com_garbage-collection-fundamentals]
+- [Jetbrains memory management concepts][jetbrains.com_memory-management-concepts]
+- [Jon skeet on C# memory allocation][jonskeet.uk_memory]
+- [Pro .NET memory management (book)][pro-dotnet-memory]
+
+[docs.microsoft.com_garbage-collection-fundamentals]: https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
+[jonskeet.uk_memory]: https://jonskeet.uk/csharp/memory.html
+[jetbrains.com_memory-management-concepts]: https://www.jetbrains.com/help/dotmemory/NET_Memory_Management_Concepts.html
+[pro-dotnet-memory]: https://prodotnetmemory.com/

From d6e1ff2a8a7939bcac1b10112b4b579d43eda64b Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Wed, 20 Jan 2021 04:16:32 -0500
Subject: [PATCH 294/327] luciens-lasagna/basics story fix

manual construction of about.md to avoid merge conflicts

* basics-story-fix enhanced instructions for luciens-lasagna
---
 .../concept/lucians-luscious-lasagna/.docs/instructions.md    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md b/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
index d761d505bb..a97d3450cf 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
@@ -1,4 +1,6 @@
-In this exercise you're going to write some code to help you cook a brilliant lasagna from your favorite cooking book.
+Lucian's girlfriend is on her way home and he hasn't cooked their anniversary dinner!
+
+In this exercise, you're going to write some code to help Lucian cook an exquisite lasagna from his favorite cook book.
 
 You have four tasks, all related to the time spent cooking the lasagna.
 

From 567dd9a5fbef326d5edd3f30e6a64d6ecedf549a Mon Sep 17 00:00:00 2001
From: Mike May 
Date: Wed, 20 Jan 2021 12:28:57 -0500
Subject: [PATCH 295/327] ensure that all basics concepts are mentioned in
 about.md and files are consistent

manual construction of about.md to avoid merge conflicts

* basics ensure all concepts identified for the basics story are included

* basics ensure all concepts identified for the basics story are included

* basics ensure all concepts identified for the basics story are included in about.md but as sub-concepts for basics

* basics better link for functions

* basics address review points

* [CI] Format code

Co-authored-by: github-actions[bot] 
---
 concepts/basics/about.md                      | 12 +++-
 .../lucians-luscious-lasagna/.meta/design.md  | 13 +----
 reference/exercises.json                      | 56 +++----------------
 3 files changed, 19 insertions(+), 62 deletions(-)

diff --git a/concepts/basics/about.md b/concepts/basics/about.md
index 6748f22a9e..e97a237064 100644
--- a/concepts/basics/about.md
+++ b/concepts/basics/about.md
@@ -1,4 +1,4 @@
-C# is a statically-typed language, which means that everything has a type at compile-time. Choosing a name for a variable is referred to as defining a variable. Once a variable is defined, setting or updating a value is called variable assignment. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value.
+C# is a statically-typed language, which means that everything has a type at compile-time. Choosing a name for a [variable][variable] is referred to as defining a variable. Once a variable is defined, setting or updating a value is called variable assignment. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value. The use of `var` is known as _type inference_.
 
 ```csharp
 int explicitVar = 10; // Explicitly typed
@@ -15,7 +15,7 @@ count = 2;     // Update to new value
 // count = false;
 ```
 
-C# is an object-oriented language and requires all functions to be defined in a _class_, which are defined using the [`class` keyword][classes]. Objects (or _instances_) are created by using the `new` keyword.
+C# is an object-oriented language and requires all [functions][function] to be defined in a _class_, which are defined using the [`class` keyword][classes]. Objects (or _instances_) are created by using the `new` keyword.
 
 ```csharp
 class Calculator
@@ -70,7 +70,9 @@ C# supports two types of [comments][comments]. Single line comments are preceded
 
 Integer values are defined as one or more (consecutive) digits and support the [default mathematical operators][operators].
 
-A variable name [must follow some rules][identifier-names] like starting either by a letter or an underscore, and [should follow C# naming convention][naming-guidelines]. If a variable name collides with a reserved [C# keyword][csharp-keywords], it must be escaped using `@`. It is not recommended to use that notation, but it can be encountered in exceptional cases, for example: `var @this`, `var @class` or `var @var`.
+A variable name [must follow some rules][identifier-names] like starting either by a letter or an underscore, and [should follow C# naming convention][naming-guidelines]. If a variable name collides with a reserved [C# keyword][csharp-keywords], it must be escaped using `@`. Use of that notation is not recommended, but it can be encountered in exceptional cases, for example: `var @this`, `var @class` or `var @var`.
+
+There are a couple of concepts that are so fundamental to a C-family language like C# that they occur naturally in almost any piece of non-trivial code. These are [mutation][mutation] and [scope][scope]. Mutation is the idea that a variable can have its value changed in the course of a program's lifetime. Scope is the idea that the value associated with a name (of a program element) is only accessible within the code "area" where it is defined. The principal code areas in C# are _class/struct_ and _function_ (typically methods) but can also include the bodies of loops and other constructs.
 
 [assignment]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/assignment-operator
 [var]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/var
@@ -82,3 +84,7 @@ A variable name [must follow some rules][identifier-names] like starting either
 [identifier-names]: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/identifier-names
 [naming-guidelines]: https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/naming-guidelines
 [csharp-keywords]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/
+[variable]: https://www.guru99.com/c-sharp-variables-operator.html
+[function]: https://csharp.net-tutorials.com/classes/methods/
+[mutation]: https://benmccormick.org/2016/06/04/what-are-mutable-and-immutable-data-structures-2
+[scope]: https://www.geeksforgeeks.org/scope-of-variables-in-c-sharp/
diff --git a/exercises/concept/lucians-luscious-lasagna/.meta/design.md b/exercises/concept/lucians-luscious-lasagna/.meta/design.md
index 860e6014d1..1247b30df9 100644
--- a/exercises/concept/lucians-luscious-lasagna/.meta/design.md
+++ b/exercises/concept/lucians-luscious-lasagna/.meta/design.md
@@ -9,7 +9,7 @@
 - Know how to call a method
 - Know that methods must be defined in classes
 - Know about the `public` access modifier
-- Know about the `static` modifier (only in concept's `about.md`)
+- Know about the `static` modifier (only in the concept's `about.md`)
 - Know how to define an integer
 - Know how to use mathematical operators on integers
 - Know how to define single- and multiline comments
@@ -30,14 +30,7 @@
 
 ## Concepts
 
-- `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments.
-- `type-inference`: know how to use the keyword, `var`; know when it is appropriate to use type-inference
-- `return-values`: know the syntax of the return statement
-- `mutation`: know how OO state is maintained and updated in C#
-- `functions`: know the syntax of a function call; know the syntax of a function declaration; understand the role of functions within OO
-- `comments`: know the syntax of a single line comment; know the syntax of a multi-line comment
-- `scoping`: know how scope works, what is in scope and out of scope at any point in the code
-- `variables`: know how to declare a variable; know how to use a variable
+- `basics`: know what a variable is; know how to define a variable; know how to update a variable; know how to use type inference for variables; know how to define a method; know how to return a value from a method; know how to call a method; know that methods must be defined in classes; know about the `public` access modifier; know about the `static` modifier; know how to define an integer; know how to use mathematical operators on integers; know how to define single- and multiline comments. The following sub-concepts are included `type-inference`, `return-values`, `mutation`, `functions`, `comments`, `scoping`, `variables`
 
 ## Prerequisites
 
@@ -45,7 +38,7 @@ There are no prerequisites.
 
 ## Analyzer
 
-This exercise could benefit from the following rules added to the the [analyzer][analyzer]:
+This exercise could benefit from the following rules added to the [analyzer][analyzer]:
 
 - Verify that the `RemainingMinutesInOven()` method calls the `ExpectedMinutesInOven()` method.
 - Verify that the `ElapsedTimeInMinutes()` method calls the `PreparationTimeInMinutes()` method.
diff --git a/reference/exercises.json b/reference/exercises.json
index d456db1a42..ecaab3e38a 100644
--- a/reference/exercises.json
+++ b/reference/exercises.json
@@ -88,73 +88,31 @@
             {
               "name": " basics (including methods)",
               "line-number": 20
-            }
-          ]
-        },
-        {
-          "name": "return-values",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "  - Return values",
               "line-number": 30
-            }
-          ]
-        },
-        {
-          "name": "mutation",
-          "track-neutral-concept": "reference/concepts/mutation.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Mutation][mutation]",
               "line-number": 31
-            }
-          ]
-        },
-        {
-          "name": "functions",
-          "track-neutral-concept": "reference/types/function.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Functions][functions]",
               "line-number": 46
-            }
-          ]
-        },
-        {
-          "name": "type-inference",
-          "track-neutral-concept": "reference/concepts/type_inference.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Type inference][type_inference]",
               "line-number": 61
-            }
-          ]
-        },
-        {
-          "name": "comments",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "- Comments",
               "line-number": 78
-            }
-          ]
-        },
-        {
-          "name": "scoping",
-          "track-neutral-concept": "",
-          "original-concepts": [
+            },
             {
               "name": "- Scoping",
               "line-number": 120
-            }
-          ]
-        },
-        {
-          "name": "variables",
-          "track-neutral-concept": "reference/concepts/variables.md",
-          "original-concepts": [
+            },
             {
               "name": "- [Variables][variables]",
               "line-number": 131

From 8f33c418df32bbee1f03f022a7cef7def15b205d Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Thu, 28 Jan 2021 14:12:05 +0100
Subject: [PATCH 296/327] Convert example to exemplar

* Rename example files to exemplar

See https://github.com/exercism/v3-docs/pull/23

* [Docs] Correct .meta/example references to .meta/exemplar

* [Docs] Use exemplar instead of example

* [Docs] Update example name in file listings

* [Julia] Convert to exemplar.jl

* [elm] Rename .meta/Cook.elm to .meta/Examplar.elm

* [elm] Rename .meta/Examplar.elm .meta/Exemplar.elm

Co-authored-by: Matthieu Pizenberg 
---
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../bird-watcher/.meta/{Example.cs => Exemplar.cs}        | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../building-telemetry/.meta/{Example.cs => Exemplar.cs}  | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../cars-assemble/.meta/{Example.cs => Exemplar.cs}       | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../concept/elons-toys/.meta/{Example.cs => Exemplar.cs}  | 0
 .../concept/faceid-2/.meta/{Example.cs => Exemplar.cs}    | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../hyperia-forex/.meta/{Example.cs => Exemplar.cs}       | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../land-grab-in-space/.meta/{Example.cs => Exemplar.cs}  | 0
 .../concept/log-levels/.meta/{Example.cs => Exemplar.cs}  | 0
 .../logs-logs-logs/.meta/{Example.cs => Exemplar.cs}      | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../need-for-speed/.meta/{Example.cs => Exemplar.cs}      | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../orm-in-one-go/.meta/{Example.cs => Exemplar.cs}       | 0
 .../parsing-log-files/.meta/{Example.cs => Exemplar.cs}   | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../roll-the-die/.meta/{Example.cs => Exemplar.cs}        | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../squeaky-clean/.meta/{Example.cs => Exemplar.cs}       | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../tim-from-marketing/.meta/{Example.cs => Exemplar.cs}  | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../weighing-machine/.meta/{Example.cs => Exemplar.cs}    | 0
 exercises/concept/weighing-machine/.meta/design.md        | 4 ++--
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 .../.meta/{Example.cs => Exemplar.cs}                     | 0
 reference/implementing-a-concept-exercise.md              | 8 ++++----
 43 files changed, 6 insertions(+), 6 deletions(-)
 rename exercises/concept/annalyns-infiltration/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/attack-of-the-trolls/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/authentication-system/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/beauty-salon-goes-global/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/bird-watcher/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/booking-up-for-beauty/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/building-telemetry/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/calculator-conundrum/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/cars-assemble/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/developer-privileges/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/elons-toys/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/faceid-2/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/football-match-reports/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/high-school-sweethearts/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/hyper-optimized-telemetry/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/hyperia-forex/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/hyperinflation-hits-hyperia/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/instruments-of-texas/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/interest-is-interesting/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/international-calling-connoisseur/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/land-grab-in-space/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/log-levels/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/logs-logs-logs/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/lucians-luscious-lasagna/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/need-for-speed/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/object-relational-mapping/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/orm-in-one-go/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/parsing-log-files/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/phone-number-analysis/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/red-vs-blue-darwin-style/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/remote-control-cleanup/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/remote-control-competition/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/roll-the-die/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/secure-munchester-united/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/squeaky-clean/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/the-weather-in-deather/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/tim-from-marketing/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/tracks-on-tracks-on-tracks/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/weighing-machine/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/wizards-and-warriors-2/.meta/{Example.cs => Exemplar.cs} (100%)
 rename exercises/concept/wizards-and-warriors/.meta/{Example.cs => Exemplar.cs} (100%)

diff --git a/exercises/concept/annalyns-infiltration/.meta/Example.cs b/exercises/concept/annalyns-infiltration/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/annalyns-infiltration/.meta/Example.cs
rename to exercises/concept/annalyns-infiltration/.meta/Exemplar.cs
diff --git a/exercises/concept/attack-of-the-trolls/.meta/Example.cs b/exercises/concept/attack-of-the-trolls/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/attack-of-the-trolls/.meta/Example.cs
rename to exercises/concept/attack-of-the-trolls/.meta/Exemplar.cs
diff --git a/exercises/concept/authentication-system/.meta/Example.cs b/exercises/concept/authentication-system/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/authentication-system/.meta/Example.cs
rename to exercises/concept/authentication-system/.meta/Exemplar.cs
diff --git a/exercises/concept/beauty-salon-goes-global/.meta/Example.cs b/exercises/concept/beauty-salon-goes-global/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/beauty-salon-goes-global/.meta/Example.cs
rename to exercises/concept/beauty-salon-goes-global/.meta/Exemplar.cs
diff --git a/exercises/concept/bird-watcher/.meta/Example.cs b/exercises/concept/bird-watcher/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/bird-watcher/.meta/Example.cs
rename to exercises/concept/bird-watcher/.meta/Exemplar.cs
diff --git a/exercises/concept/booking-up-for-beauty/.meta/Example.cs b/exercises/concept/booking-up-for-beauty/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/booking-up-for-beauty/.meta/Example.cs
rename to exercises/concept/booking-up-for-beauty/.meta/Exemplar.cs
diff --git a/exercises/concept/building-telemetry/.meta/Example.cs b/exercises/concept/building-telemetry/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/building-telemetry/.meta/Example.cs
rename to exercises/concept/building-telemetry/.meta/Exemplar.cs
diff --git a/exercises/concept/calculator-conundrum/.meta/Example.cs b/exercises/concept/calculator-conundrum/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/calculator-conundrum/.meta/Example.cs
rename to exercises/concept/calculator-conundrum/.meta/Exemplar.cs
diff --git a/exercises/concept/cars-assemble/.meta/Example.cs b/exercises/concept/cars-assemble/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/cars-assemble/.meta/Example.cs
rename to exercises/concept/cars-assemble/.meta/Exemplar.cs
diff --git a/exercises/concept/developer-privileges/.meta/Example.cs b/exercises/concept/developer-privileges/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/developer-privileges/.meta/Example.cs
rename to exercises/concept/developer-privileges/.meta/Exemplar.cs
diff --git a/exercises/concept/elons-toys/.meta/Example.cs b/exercises/concept/elons-toys/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/elons-toys/.meta/Example.cs
rename to exercises/concept/elons-toys/.meta/Exemplar.cs
diff --git a/exercises/concept/faceid-2/.meta/Example.cs b/exercises/concept/faceid-2/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/faceid-2/.meta/Example.cs
rename to exercises/concept/faceid-2/.meta/Exemplar.cs
diff --git a/exercises/concept/football-match-reports/.meta/Example.cs b/exercises/concept/football-match-reports/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/football-match-reports/.meta/Example.cs
rename to exercises/concept/football-match-reports/.meta/Exemplar.cs
diff --git a/exercises/concept/high-school-sweethearts/.meta/Example.cs b/exercises/concept/high-school-sweethearts/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/high-school-sweethearts/.meta/Example.cs
rename to exercises/concept/high-school-sweethearts/.meta/Exemplar.cs
diff --git a/exercises/concept/hyper-optimized-telemetry/.meta/Example.cs b/exercises/concept/hyper-optimized-telemetry/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/hyper-optimized-telemetry/.meta/Example.cs
rename to exercises/concept/hyper-optimized-telemetry/.meta/Exemplar.cs
diff --git a/exercises/concept/hyperia-forex/.meta/Example.cs b/exercises/concept/hyperia-forex/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/hyperia-forex/.meta/Example.cs
rename to exercises/concept/hyperia-forex/.meta/Exemplar.cs
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.meta/Example.cs b/exercises/concept/hyperinflation-hits-hyperia/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/hyperinflation-hits-hyperia/.meta/Example.cs
rename to exercises/concept/hyperinflation-hits-hyperia/.meta/Exemplar.cs
diff --git a/exercises/concept/instruments-of-texas/.meta/Example.cs b/exercises/concept/instruments-of-texas/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/instruments-of-texas/.meta/Example.cs
rename to exercises/concept/instruments-of-texas/.meta/Exemplar.cs
diff --git a/exercises/concept/interest-is-interesting/.meta/Example.cs b/exercises/concept/interest-is-interesting/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/interest-is-interesting/.meta/Example.cs
rename to exercises/concept/interest-is-interesting/.meta/Exemplar.cs
diff --git a/exercises/concept/international-calling-connoisseur/.meta/Example.cs b/exercises/concept/international-calling-connoisseur/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/international-calling-connoisseur/.meta/Example.cs
rename to exercises/concept/international-calling-connoisseur/.meta/Exemplar.cs
diff --git a/exercises/concept/land-grab-in-space/.meta/Example.cs b/exercises/concept/land-grab-in-space/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/land-grab-in-space/.meta/Example.cs
rename to exercises/concept/land-grab-in-space/.meta/Exemplar.cs
diff --git a/exercises/concept/log-levels/.meta/Example.cs b/exercises/concept/log-levels/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/log-levels/.meta/Example.cs
rename to exercises/concept/log-levels/.meta/Exemplar.cs
diff --git a/exercises/concept/logs-logs-logs/.meta/Example.cs b/exercises/concept/logs-logs-logs/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/logs-logs-logs/.meta/Example.cs
rename to exercises/concept/logs-logs-logs/.meta/Exemplar.cs
diff --git a/exercises/concept/lucians-luscious-lasagna/.meta/Example.cs b/exercises/concept/lucians-luscious-lasagna/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/lucians-luscious-lasagna/.meta/Example.cs
rename to exercises/concept/lucians-luscious-lasagna/.meta/Exemplar.cs
diff --git a/exercises/concept/need-for-speed/.meta/Example.cs b/exercises/concept/need-for-speed/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/need-for-speed/.meta/Example.cs
rename to exercises/concept/need-for-speed/.meta/Exemplar.cs
diff --git a/exercises/concept/object-relational-mapping/.meta/Example.cs b/exercises/concept/object-relational-mapping/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/object-relational-mapping/.meta/Example.cs
rename to exercises/concept/object-relational-mapping/.meta/Exemplar.cs
diff --git a/exercises/concept/orm-in-one-go/.meta/Example.cs b/exercises/concept/orm-in-one-go/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/orm-in-one-go/.meta/Example.cs
rename to exercises/concept/orm-in-one-go/.meta/Exemplar.cs
diff --git a/exercises/concept/parsing-log-files/.meta/Example.cs b/exercises/concept/parsing-log-files/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/parsing-log-files/.meta/Example.cs
rename to exercises/concept/parsing-log-files/.meta/Exemplar.cs
diff --git a/exercises/concept/phone-number-analysis/.meta/Example.cs b/exercises/concept/phone-number-analysis/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/phone-number-analysis/.meta/Example.cs
rename to exercises/concept/phone-number-analysis/.meta/Exemplar.cs
diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs b/exercises/concept/red-vs-blue-darwin-style/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/red-vs-blue-darwin-style/.meta/Example.cs
rename to exercises/concept/red-vs-blue-darwin-style/.meta/Exemplar.cs
diff --git a/exercises/concept/remote-control-cleanup/.meta/Example.cs b/exercises/concept/remote-control-cleanup/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/remote-control-cleanup/.meta/Example.cs
rename to exercises/concept/remote-control-cleanup/.meta/Exemplar.cs
diff --git a/exercises/concept/remote-control-competition/.meta/Example.cs b/exercises/concept/remote-control-competition/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/remote-control-competition/.meta/Example.cs
rename to exercises/concept/remote-control-competition/.meta/Exemplar.cs
diff --git a/exercises/concept/roll-the-die/.meta/Example.cs b/exercises/concept/roll-the-die/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/roll-the-die/.meta/Example.cs
rename to exercises/concept/roll-the-die/.meta/Exemplar.cs
diff --git a/exercises/concept/secure-munchester-united/.meta/Example.cs b/exercises/concept/secure-munchester-united/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/secure-munchester-united/.meta/Example.cs
rename to exercises/concept/secure-munchester-united/.meta/Exemplar.cs
diff --git a/exercises/concept/squeaky-clean/.meta/Example.cs b/exercises/concept/squeaky-clean/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/squeaky-clean/.meta/Example.cs
rename to exercises/concept/squeaky-clean/.meta/Exemplar.cs
diff --git a/exercises/concept/the-weather-in-deather/.meta/Example.cs b/exercises/concept/the-weather-in-deather/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/the-weather-in-deather/.meta/Example.cs
rename to exercises/concept/the-weather-in-deather/.meta/Exemplar.cs
diff --git a/exercises/concept/tim-from-marketing/.meta/Example.cs b/exercises/concept/tim-from-marketing/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/tim-from-marketing/.meta/Example.cs
rename to exercises/concept/tim-from-marketing/.meta/Exemplar.cs
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.meta/Example.cs b/exercises/concept/tracks-on-tracks-on-tracks/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/tracks-on-tracks-on-tracks/.meta/Example.cs
rename to exercises/concept/tracks-on-tracks-on-tracks/.meta/Exemplar.cs
diff --git a/exercises/concept/weighing-machine/.meta/Example.cs b/exercises/concept/weighing-machine/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/weighing-machine/.meta/Example.cs
rename to exercises/concept/weighing-machine/.meta/Exemplar.cs
diff --git a/exercises/concept/weighing-machine/.meta/design.md b/exercises/concept/weighing-machine/.meta/design.md
index f52ac0d9f7..648f8a0120 100644
--- a/exercises/concept/weighing-machine/.meta/design.md
+++ b/exercises/concept/weighing-machine/.meta/design.md
@@ -117,7 +117,7 @@ languages
                 |   └── introduction.md
                 ├── .meta
                 |   ├── design.md
-                |   └── Example.cs
+                |   └── Exemplar.cs
                 ├── Properties.csproj
                 ├── Properties.cs
                 └── PropertiesTest.cs
@@ -169,7 +169,7 @@ These files are specific to the C# track:
 - `Properties.csproj`: the C# project file.
 - `PropertiesTest.cs`: the test suite.
 - `Properties.cs`. the stub implementation file, which is the starting point for students to work on the exercise.
-- `.meta/Example.cs`: an example implementation that passes all the tests.
+- `.meta/Exemplar.cs`: an exemplar implementation that passes all the tests.
 
 Check out the [`floating-point-numbers exercise`][csharp-docs-concept-exercises-numbers-floating-point] for an example on what these files should look like.
 
diff --git a/exercises/concept/wizards-and-warriors-2/.meta/Example.cs b/exercises/concept/wizards-and-warriors-2/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/wizards-and-warriors-2/.meta/Example.cs
rename to exercises/concept/wizards-and-warriors-2/.meta/Exemplar.cs
diff --git a/exercises/concept/wizards-and-warriors/.meta/Example.cs b/exercises/concept/wizards-and-warriors/.meta/Exemplar.cs
similarity index 100%
rename from exercises/concept/wizards-and-warriors/.meta/Example.cs
rename to exercises/concept/wizards-and-warriors/.meta/Exemplar.cs
diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md
index 99a5d0a9e5..50fa355346 100644
--- a/reference/implementing-a-concept-exercise.md
+++ b/reference/implementing-a-concept-exercise.md
@@ -40,7 +40,7 @@ languages
                 ├── .meta
                 |   |── config.json
                 |   |── design.md
-                |   └── Example.cs
+                |   └── Exemplar.cs
                 ├── <NAME>.cs
                 ├── <NAME>.csproj
                 └── <NAME>Tests.cs
@@ -77,7 +77,7 @@ For more information, please read [this in-depth description][tests-file], [watc
 
 For more information, check [this example project file][example-project-file].
 
-### Add `.meta/Example.cs` file
+### Add `.meta/Exemplar.cs` file
 
 **Purpose:** The idiomatic example implementation that passes all the tests.
 
@@ -145,7 +145,7 @@ If you have any questions regarding implementing the exercise, please post them
 [video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781
 [example-stub-file]: ../exercises/concept/log-levels/LogLevels.cs
 [example-tests-file]: ../exercises/concept/log-levels/LogLevelsTests.cs
-[example-example-file]: ../exercises/concept/log-levels/.meta/Example.cs
+[example-example-file]: ../exercises/concept/log-levels/.meta/Exemplar.cs
 [example-project-file]: ../exercises/concept/log-levels/LogLevels.csproj
 [skip-fact]: ../exercises/concept/log-levels/LogLevelsTests.cs#L11
 [test-name]: ../exercises/concept/log-levels/LogLevelsTests.cs#L24
@@ -161,5 +161,5 @@ If you have any questions regarding implementing the exercise, please post them
 [video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781
 [example-stub-file]: ../languages/csharp/exercises/concept/log-levels/LogLevels.cs
 [example-tests-file]: ../languages/csharp/exercises/concept/log-levels/LogLevelsTests.cs
-[example-example-file]: ../languages/csharp/exercises/concept/log-levels/.meta/Example.cs
+[example-example-file]: ../languages/csharp/exercises/concept/log-levels/.meta/Exemplar.cs
 [example-project-file]: ../exercises/concept/log-levels/LogLevels.csproj

From b865b2ffe2c3192f35bd189f284057d8e46fcc09 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 08:37:42 +0100
Subject: [PATCH 297/327] Convert editor key in .meta/config.json files

* Convert editor key to files

* Add missing "files" field to .meta/config.json files

* Add exemplar files to .meta/config.json

* Add common-lisp exemplar to template
---
 exercises/concept/annalyns-infiltration/.meta/config.json  | 7 ++++---
 exercises/concept/attack-of-the-trolls/.meta/config.json   | 7 ++++---
 exercises/concept/authentication-system/.meta/config.json  | 7 ++++---
 .../concept/beauty-salon-goes-global/.meta/config.json     | 7 ++++---
 exercises/concept/bird-watcher/.meta/config.json           | 7 ++++---
 exercises/concept/booking-up-for-beauty/.meta/config.json  | 7 ++++---
 exercises/concept/building-telemetry/.meta/config.json     | 7 ++++---
 exercises/concept/calculator-conundrum/.meta/config.json   | 7 ++++---
 exercises/concept/cars-assemble/.meta/config.json          | 7 ++++---
 exercises/concept/developer-privileges/.meta/config.json   | 7 ++++---
 exercises/concept/elons-toys/.meta/config.json             | 7 ++++---
 exercises/concept/faceid-2/.meta/config.json               | 7 ++++---
 exercises/concept/football-match-reports/.meta/config.json | 7 ++++---
 .../concept/high-school-sweethearts/.meta/config.json      | 7 ++++---
 .../concept/hyper-optimized-telemetry/.meta/config.json    | 7 ++++---
 exercises/concept/hyperia-forex/.meta/config.json          | 7 ++++---
 .../concept/hyperinflation-hits-hyperia/.meta/config.json  | 7 ++++---
 exercises/concept/instruments-of-texas/.meta/config.json   | 7 ++++---
 .../concept/interest-is-interesting/.meta/config.json      | 7 ++++---
 .../international-calling-connoisseur/.meta/config.json    | 7 ++++---
 exercises/concept/land-grab-in-space/.meta/config.json     | 7 ++++---
 exercises/concept/log-levels/.meta/config.json             | 7 ++++---
 exercises/concept/logs-logs-logs/.meta/config.json         | 7 ++++---
 .../concept/lucians-luscious-lasagna/.meta/config.json     | 7 ++++---
 exercises/concept/need-for-speed/.meta/config.json         | 7 ++++---
 .../concept/object-relational-mapping/.meta/config.json    | 7 ++++---
 exercises/concept/orm-in-one-go/.meta/config.json          | 7 ++++---
 exercises/concept/parsing-log-files/.meta/config.json      | 7 ++++---
 exercises/concept/phone-number-analysis/.meta/config.json  | 7 ++++---
 .../concept/red-vs-blue-darwin-style/.meta/config.json     | 7 ++++---
 exercises/concept/remote-control-cleanup/.meta/config.json | 7 ++++---
 .../concept/remote-control-competition/.meta/config.json   | 7 ++++---
 exercises/concept/roll-the-die/.meta/config.json           | 7 ++++---
 .../concept/secure-munchester-united/.meta/config.json     | 7 ++++---
 exercises/concept/squeaky-clean/.meta/config.json          | 7 ++++---
 exercises/concept/the-weather-in-deather/.meta/config.json | 7 ++++---
 exercises/concept/tim-from-marketing/.meta/config.json     | 7 ++++---
 .../concept/tracks-on-tracks-on-tracks/.meta/config.json   | 7 ++++---
 exercises/concept/weighing-machine/.meta/config.json       | 7 ++++---
 exercises/concept/wizards-and-warriors-2/.meta/config.json | 7 ++++---
 exercises/concept/wizards-and-warriors/.meta/config.json   | 7 ++++---
 41 files changed, 164 insertions(+), 123 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/.meta/config.json b/exercises/concept/annalyns-infiltration/.meta/config.json
index 1d189467e6..c54b278f60 100644
--- a/exercises/concept/annalyns-infiltration/.meta/config.json
+++ b/exercises/concept/annalyns-infiltration/.meta/config.json
@@ -6,8 +6,9 @@
     }
   ],
   "forked_from": ["fsharp/booleans"],
-  "editor": {
-    "solution_files": ["AnnalynsInfiltration.cs"],
-    "test_files": ["AnnalynsInfiltrationTests.cs"]
+  "files": {
+    "solution": ["AnnalynsInfiltration.cs"],
+    "test": ["AnnalynsInfiltrationTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/attack-of-the-trolls/.meta/config.json b/exercises/concept/attack-of-the-trolls/.meta/config.json
index 5319467747..c5fd8a01e0 100644
--- a/exercises/concept/attack-of-the-trolls/.meta/config.json
+++ b/exercises/concept/attack-of-the-trolls/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["AttackOfTheTrolls.cs"],
-    "test_files": ["AttackOfTheTrollsTests.cs"]
+  "files": {
+    "solution": ["AttackOfTheTrolls.cs"],
+    "test": ["AttackOfTheTrollsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/authentication-system/.meta/config.json b/exercises/concept/authentication-system/.meta/config.json
index 1642f0967f..4a621d6b65 100644
--- a/exercises/concept/authentication-system/.meta/config.json
+++ b/exercises/concept/authentication-system/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["AuthenticationSystem.cs"],
-    "test_files": ["AuthenticationSystemTests.cs"]
+  "files": {
+    "solution": ["AuthenticationSystem.cs"],
+    "test": ["AuthenticationSystemTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/beauty-salon-goes-global/.meta/config.json b/exercises/concept/beauty-salon-goes-global/.meta/config.json
index eb0e1887db..5411abe809 100644
--- a/exercises/concept/beauty-salon-goes-global/.meta/config.json
+++ b/exercises/concept/beauty-salon-goes-global/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["BeautySalonGoesGlobal.cs"],
-    "test_files": ["BeautySalonGoesGlobalTests.cs"]
+  "files": {
+    "solution": ["BeautySalonGoesGlobal.cs"],
+    "test": ["BeautySalonGoesGlobalTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/bird-watcher/.meta/config.json b/exercises/concept/bird-watcher/.meta/config.json
index 83d1f35fef..fe9e3d4abd 100644
--- a/exercises/concept/bird-watcher/.meta/config.json
+++ b/exercises/concept/bird-watcher/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["BirdWatcher.cs"],
-    "test_files": ["BirdWatcherTests.cs"]
+  "files": {
+    "solution": ["BirdWatcher.cs"],
+    "test": ["BirdWatcherTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/booking-up-for-beauty/.meta/config.json b/exercises/concept/booking-up-for-beauty/.meta/config.json
index 17c69a3217..0f5b1a8210 100644
--- a/exercises/concept/booking-up-for-beauty/.meta/config.json
+++ b/exercises/concept/booking-up-for-beauty/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["BookingUpForBeauty.cs"],
-    "test_files": ["BookingUpForBeautyTests.cs"]
+  "files": {
+    "solution": ["BookingUpForBeauty.cs"],
+    "test": ["BookingUpForBeautyTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/building-telemetry/.meta/config.json b/exercises/concept/building-telemetry/.meta/config.json
index 3f09598013..1cfb7cf569 100644
--- a/exercises/concept/building-telemetry/.meta/config.json
+++ b/exercises/concept/building-telemetry/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["BuildingTelemetry.cs"],
-    "test_files": ["BuildingTelemetryTests.cs"]
+  "files": {
+    "solution": ["BuildingTelemetry.cs"],
+    "test": ["BuildingTelemetryTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/calculator-conundrum/.meta/config.json b/exercises/concept/calculator-conundrum/.meta/config.json
index a5f95aabb7..48f2dc8bdd 100644
--- a/exercises/concept/calculator-conundrum/.meta/config.json
+++ b/exercises/concept/calculator-conundrum/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "archrisV"
     }
   ],
-  "editor": {
-    "solution_files": ["CalculatorConundrum.cs"],
-    "test_files": ["CalculatorConundrumTests.cs"]
+  "files": {
+    "solution": ["CalculatorConundrum.cs"],
+    "test": ["CalculatorConundrumTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/cars-assemble/.meta/config.json b/exercises/concept/cars-assemble/.meta/config.json
index 2247d06564..677f89147a 100644
--- a/exercises/concept/cars-assemble/.meta/config.json
+++ b/exercises/concept/cars-assemble/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["CarsAssemble.cs"],
-    "test_files": ["CarsAssembleTests.cs"]
+  "files": {
+    "solution": ["CarsAssemble.cs"],
+    "test": ["CarsAssembleTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/developer-privileges/.meta/config.json b/exercises/concept/developer-privileges/.meta/config.json
index a9d5b8209e..a0e1d4fc2f 100644
--- a/exercises/concept/developer-privileges/.meta/config.json
+++ b/exercises/concept/developer-privileges/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["WhyCantIPushToMain.cs"],
-    "test_files": ["WhyCantIPushToMainTests.cs"]
+  "files": {
+    "solution": ["WhyCantIPushToMain.cs"],
+    "test": ["WhyCantIPushToMainTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/elons-toys/.meta/config.json b/exercises/concept/elons-toys/.meta/config.json
index 98c1f143b9..7614213118 100644
--- a/exercises/concept/elons-toys/.meta/config.json
+++ b/exercises/concept/elons-toys/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["ElonsToys.cs"],
-    "test_files": ["ElonsToysTests.cs"]
+  "files": {
+    "solution": ["ElonsToys.cs"],
+    "test": ["ElonsToysTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/faceid-2/.meta/config.json b/exercises/concept/faceid-2/.meta/config.json
index 32e59905ae..1685fd09e5 100644
--- a/exercises/concept/faceid-2/.meta/config.json
+++ b/exercises/concept/faceid-2/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["Faceid2.cs"],
-    "test_files": ["Faceid2Tests.cs"]
+  "files": {
+    "solution": ["Faceid2.cs"],
+    "test": ["Faceid2Tests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/football-match-reports/.meta/config.json b/exercises/concept/football-match-reports/.meta/config.json
index 7181ca0f92..bf9ba10657 100644
--- a/exercises/concept/football-match-reports/.meta/config.json
+++ b/exercises/concept/football-match-reports/.meta/config.json
@@ -15,8 +15,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["FootballMatchReports.cs"],
-    "test_files": ["FootballMatchReportsTests.cs"]
+  "files": {
+    "solution": ["FootballMatchReports.cs"],
+    "test": ["FootballMatchReportsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/high-school-sweethearts/.meta/config.json b/exercises/concept/high-school-sweethearts/.meta/config.json
index afcbae6840..b0ea4a83f6 100644
--- a/exercises/concept/high-school-sweethearts/.meta/config.json
+++ b/exercises/concept/high-school-sweethearts/.meta/config.json
@@ -12,8 +12,9 @@
     }
   ],
   "forked_from": ["elixir/strings"],
-  "editor": {
-    "solution_files": ["HighSchoolSweethearts.cs"],
-    "test_files": ["HighSchoolSweetheartsTests.cs"]
+  "files": {
+    "solution": ["HighSchoolSweethearts.cs"],
+    "test": ["HighSchoolSweetheartsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/hyper-optimized-telemetry/.meta/config.json b/exercises/concept/hyper-optimized-telemetry/.meta/config.json
index a71a0f84a8..28c640f2cf 100644
--- a/exercises/concept/hyper-optimized-telemetry/.meta/config.json
+++ b/exercises/concept/hyper-optimized-telemetry/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["HyperOptimizedTelemetry.cs"],
-    "test_files": ["HyperOptimizedTelemetryTests.cs"]
+  "files": {
+    "solution": ["HyperOptimizedTelemetry.cs"],
+    "test": ["HyperOptimizedTelemetryTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/hyperia-forex/.meta/config.json b/exercises/concept/hyperia-forex/.meta/config.json
index 96eb928dce..fcb74ae851 100644
--- a/exercises/concept/hyperia-forex/.meta/config.json
+++ b/exercises/concept/hyperia-forex/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["HyperiaForex.cs"],
-    "test_files": ["HyperiaForexTests.cs"]
+  "files": {
+    "solution": ["HyperiaForex.cs"],
+    "test": ["HyperiaForexTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json b/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json
index 34bc954d5e..edcd03cb1c 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json
+++ b/exercises/concept/hyperinflation-hits-hyperia/.meta/config.json
@@ -23,8 +23,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["HyperinflationHitsHyperia.cs"],
-    "test_files": ["HyperinflationHitsHyperiaTests.cs"]
+  "files": {
+    "solution": ["HyperinflationHitsHyperia.cs"],
+    "test": ["HyperinflationHitsHyperiaTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/instruments-of-texas/.meta/config.json b/exercises/concept/instruments-of-texas/.meta/config.json
index b9d4523800..da266ad73d 100644
--- a/exercises/concept/instruments-of-texas/.meta/config.json
+++ b/exercises/concept/instruments-of-texas/.meta/config.json
@@ -12,8 +12,9 @@
     }
   ],
   "forked_from": ["elixir/errors"],
-  "editor": {
-    "solution_files": ["InstrumentsOfTexas.cs"],
-    "test_files": ["InstrumentsOfTexasTests.cs"]
+  "files": {
+    "solution": ["InstrumentsOfTexas.cs"],
+    "test": ["InstrumentsOfTexasTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/interest-is-interesting/.meta/config.json b/exercises/concept/interest-is-interesting/.meta/config.json
index 920a82b250..177718ac59 100644
--- a/exercises/concept/interest-is-interesting/.meta/config.json
+++ b/exercises/concept/interest-is-interesting/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["InterestIsInteresting.cs"],
-    "test_files": ["InterestIsInterestingTests.cs"]
+  "files": {
+    "solution": ["InterestIsInteresting.cs"],
+    "test": ["InterestIsInterestingTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/international-calling-connoisseur/.meta/config.json b/exercises/concept/international-calling-connoisseur/.meta/config.json
index 94df2358ec..02f89a3ea0 100644
--- a/exercises/concept/international-calling-connoisseur/.meta/config.json
+++ b/exercises/concept/international-calling-connoisseur/.meta/config.json
@@ -15,8 +15,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["InternationalCallingConnoisseur.cs"],
-    "test_files": ["InternationalCallingConnoisseurTests.cs"]
+  "files": {
+    "solution": ["InternationalCallingConnoisseur.cs"],
+    "test": ["InternationalCallingConnoisseurTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/land-grab-in-space/.meta/config.json b/exercises/concept/land-grab-in-space/.meta/config.json
index e638703ef5..933fb503a7 100644
--- a/exercises/concept/land-grab-in-space/.meta/config.json
+++ b/exercises/concept/land-grab-in-space/.meta/config.json
@@ -19,8 +19,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["LandGrabInSpace.cs"],
-    "test_files": ["LandGrabInSpaceTests.cs"]
+  "files": {
+    "solution": ["LandGrabInSpace.cs"],
+    "test": ["LandGrabInSpaceTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/log-levels/.meta/config.json b/exercises/concept/log-levels/.meta/config.json
index ce108742a4..c1bfbdda21 100644
--- a/exercises/concept/log-levels/.meta/config.json
+++ b/exercises/concept/log-levels/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["LogLevels.cs"],
-    "test_files": ["LogLevelsTests.cs"]
+  "files": {
+    "solution": ["LogLevels.cs"],
+    "test": ["LogLevelsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/logs-logs-logs/.meta/config.json b/exercises/concept/logs-logs-logs/.meta/config.json
index abf302b96c..9fe526ce68 100644
--- a/exercises/concept/logs-logs-logs/.meta/config.json
+++ b/exercises/concept/logs-logs-logs/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["LogsLogsLogs.cs"],
-    "test_files": ["LogsLogsLogsTests.cs"]
+  "files": {
+    "solution": ["LogsLogsLogs.cs"],
+    "test": ["LogsLogsLogsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/lucians-luscious-lasagna/.meta/config.json b/exercises/concept/lucians-luscious-lasagna/.meta/config.json
index d1d6d86368..6f51297da7 100644
--- a/exercises/concept/lucians-luscious-lasagna/.meta/config.json
+++ b/exercises/concept/lucians-luscious-lasagna/.meta/config.json
@@ -6,8 +6,9 @@
     }
   ],
   "forked_from": ["fsharp/basics"],
-  "editor": {
-    "solution_files": ["LuciansLusciousLasagna.cs"],
-    "test_files": ["LuciansLusciousLasagnaTests.cs"]
+  "files": {
+    "solution": ["LuciansLusciousLasagna.cs"],
+    "test": ["LuciansLusciousLasagnaTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/need-for-speed/.meta/config.json b/exercises/concept/need-for-speed/.meta/config.json
index d2d6811505..8b8c5b9e0e 100644
--- a/exercises/concept/need-for-speed/.meta/config.json
+++ b/exercises/concept/need-for-speed/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["NeedForSpeed.cs"],
-    "test_files": ["NeedForSpeedTests.cs"]
+  "files": {
+    "solution": ["NeedForSpeed.cs"],
+    "test": ["NeedForSpeedTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/object-relational-mapping/.meta/config.json b/exercises/concept/object-relational-mapping/.meta/config.json
index 9f45774b41..dc26bb2161 100644
--- a/exercises/concept/object-relational-mapping/.meta/config.json
+++ b/exercises/concept/object-relational-mapping/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["ObjectRelationalMapping.cs"],
-    "test_files": ["ObjectRelationalMappingTests.cs"]
+  "files": {
+    "solution": ["ObjectRelationalMapping.cs"],
+    "test": ["ObjectRelationalMappingTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/orm-in-one-go/.meta/config.json b/exercises/concept/orm-in-one-go/.meta/config.json
index 30c55d319e..4f6f39eb78 100644
--- a/exercises/concept/orm-in-one-go/.meta/config.json
+++ b/exercises/concept/orm-in-one-go/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["OrmInOneGo.cs"],
-    "test_files": ["OrmInOneGoTests.cs"]
+  "files": {
+    "solution": ["OrmInOneGo.cs"],
+    "test": ["OrmInOneGoTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/parsing-log-files/.meta/config.json b/exercises/concept/parsing-log-files/.meta/config.json
index 76dedb1f8b..12c3018325 100644
--- a/exercises/concept/parsing-log-files/.meta/config.json
+++ b/exercises/concept/parsing-log-files/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["ParsingLogFiles.cs"],
-    "test_files": ["ParsingLogFilesTests.cs"]
+  "files": {
+    "solution": ["ParsingLogFiles.cs"],
+    "test": ["ParsingLogFilesTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/phone-number-analysis/.meta/config.json b/exercises/concept/phone-number-analysis/.meta/config.json
index d8a4b32c0c..5c9c773900 100644
--- a/exercises/concept/phone-number-analysis/.meta/config.json
+++ b/exercises/concept/phone-number-analysis/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["PhoneNumberAnalysis.cs"],
-    "test_files": ["PhoneNumberAnalysisTests.cs"]
+  "files": {
+    "solution": ["PhoneNumberAnalysis.cs"],
+    "test": ["PhoneNumberAnalysisTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/config.json b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
index 9092ce1688..fa041c187b 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
+++ b/exercises/concept/red-vs-blue-darwin-style/.meta/config.json
@@ -15,8 +15,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["RedVsBlueDarwinStyle.cs"],
-    "test_files": ["RedVsBlueDarwinStyleTests.cs"]
+  "files": {
+    "solution": ["RedVsBlueDarwinStyle.cs"],
+    "test": ["RedVsBlueDarwinStyleTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/remote-control-cleanup/.meta/config.json b/exercises/concept/remote-control-cleanup/.meta/config.json
index be0ef37bb4..8c6574930e 100644
--- a/exercises/concept/remote-control-cleanup/.meta/config.json
+++ b/exercises/concept/remote-control-cleanup/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["RemoteControlCleanup.cs"],
-    "test_files": ["RemoteControlCleanupTests.cs"]
+  "files": {
+    "solution": ["RemoteControlCleanup.cs"],
+    "test": ["RemoteControlCleanupTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/remote-control-competition/.meta/config.json b/exercises/concept/remote-control-competition/.meta/config.json
index 4b9e9a526b..d4e35664bb 100644
--- a/exercises/concept/remote-control-competition/.meta/config.json
+++ b/exercises/concept/remote-control-competition/.meta/config.json
@@ -15,8 +15,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["RemoteControlCompetition.cs"],
-    "test_files": ["RemoteControlCompetitionTests.cs"]
+  "files": {
+    "solution": ["RemoteControlCompetition.cs"],
+    "test": ["RemoteControlCompetitionTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/roll-the-die/.meta/config.json b/exercises/concept/roll-the-die/.meta/config.json
index 205728592c..80f6669f83 100644
--- a/exercises/concept/roll-the-die/.meta/config.json
+++ b/exercises/concept/roll-the-die/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["RollTheDie.cs"],
-    "test_files": ["RollTheDieTests.cs"]
+  "files": {
+    "solution": ["RollTheDie.cs"],
+    "test": ["RollTheDieTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/secure-munchester-united/.meta/config.json b/exercises/concept/secure-munchester-united/.meta/config.json
index bf3ee251d0..3a331c2710 100644
--- a/exercises/concept/secure-munchester-united/.meta/config.json
+++ b/exercises/concept/secure-munchester-united/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["SecureMunchesterUnited.cs"],
-    "test_files": ["SecureMunchesterUnitedTests.cs"]
+  "files": {
+    "solution": ["SecureMunchesterUnited.cs"],
+    "test": ["SecureMunchesterUnitedTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/squeaky-clean/.meta/config.json b/exercises/concept/squeaky-clean/.meta/config.json
index da2d0ddd3d..882c67d8eb 100644
--- a/exercises/concept/squeaky-clean/.meta/config.json
+++ b/exercises/concept/squeaky-clean/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["SqueakyClean.cs"],
-    "test_files": ["SqueakyCleanTests.cs"]
+  "files": {
+    "solution": ["SqueakyClean.cs"],
+    "test": ["SqueakyCleanTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/the-weather-in-deather/.meta/config.json b/exercises/concept/the-weather-in-deather/.meta/config.json
index fc9c5aa1f8..e45832a3f2 100644
--- a/exercises/concept/the-weather-in-deather/.meta/config.json
+++ b/exercises/concept/the-weather-in-deather/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["TheWeatherInDeather.cs"],
-    "test_files": ["TheWeatherInDeatherTests.cs"]
+  "files": {
+    "solution": ["TheWeatherInDeather.cs"],
+    "test": ["TheWeatherInDeatherTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/tim-from-marketing/.meta/config.json b/exercises/concept/tim-from-marketing/.meta/config.json
index ecf6fb2acd..d3627502df 100644
--- a/exercises/concept/tim-from-marketing/.meta/config.json
+++ b/exercises/concept/tim-from-marketing/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "maurelio1234"
     }
   ],
-  "editor": {
-    "solution_files": ["TimFromMarketing.cs"],
-    "test_files": ["TimFromMarketingTests.cs"]
+  "files": {
+    "solution": ["TimFromMarketing.cs"],
+    "test": ["TimFromMarketingTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json b/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json
index 35e32ebd6b..1836e8a134 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.meta/config.json
@@ -12,8 +12,9 @@
     }
   ],
   "forked_from": ["fsharp/lists"],
-  "editor": {
-    "solution_files": ["TracksOnTracksOnTracks.cs"],
-    "test_files": ["TracksOnTracksOnTracksTests.cs"]
+  "files": {
+    "solution": ["TracksOnTracksOnTracks.cs"],
+    "test": ["TracksOnTracksOnTracksTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/weighing-machine/.meta/config.json b/exercises/concept/weighing-machine/.meta/config.json
index 7228268a50..ac7232264a 100644
--- a/exercises/concept/weighing-machine/.meta/config.json
+++ b/exercises/concept/weighing-machine/.meta/config.json
@@ -11,8 +11,9 @@
       "exercism_username": "mikedamay"
     }
   ],
-  "editor": {
-    "solution_files": ["WeighingMachine.cs"],
-    "test_files": ["WeighingMachineTests.cs"]
+  "files": {
+    "solution": ["WeighingMachine.cs"],
+    "test": ["WeighingMachineTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/wizards-and-warriors-2/.meta/config.json b/exercises/concept/wizards-and-warriors-2/.meta/config.json
index aad840f568..f3ea9fdedb 100644
--- a/exercises/concept/wizards-and-warriors-2/.meta/config.json
+++ b/exercises/concept/wizards-and-warriors-2/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["WizardsAndWarriors2.cs"],
-    "test_files": ["WizardsAndWarriors2Tests.cs"]
+  "files": {
+    "solution": ["WizardsAndWarriors2.cs"],
+    "test": ["WizardsAndWarriors2Tests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }
diff --git a/exercises/concept/wizards-and-warriors/.meta/config.json b/exercises/concept/wizards-and-warriors/.meta/config.json
index b1d36e5d3f..0df6e5e5bf 100644
--- a/exercises/concept/wizards-and-warriors/.meta/config.json
+++ b/exercises/concept/wizards-and-warriors/.meta/config.json
@@ -5,8 +5,9 @@
       "exercism_username": "ErikSchierboom"
     }
   ],
-  "editor": {
-    "solution_files": ["WizardsAndWarriors.cs"],
-    "test_files": ["WizardsAndWarriorsTests.cs"]
+  "files": {
+    "solution": ["WizardsAndWarriors.cs"],
+    "test": ["WizardsAndWarriorsTests.cs"],
+    "exemplar": [".meta/Exemplar.cs"]
   }
 }

From 0a5c96eaa482f70c6fe393abb51903a8eae66ec7 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:48 +0100
Subject: [PATCH 298/327] [v3] Move existing exercises to exercises/practice

---
 .../{ => practice}/accumulate/.editorconfig   |  0
 .../{ => practice}/accumulate/.meta/hints.md  |  0
 .../{ => practice}/accumulate/Accumulate.cs   |  0
 .../accumulate/Accumulate.csproj              |  0
 .../accumulate/AccumulateTests.cs             |  0
 .../{ => practice}/accumulate/Example.cs      |  0
 exercises/{ => practice}/accumulate/README.md |  0
 .../{ => practice}/acronym/.editorconfig      |  0
 .../{ => practice}/acronym/.meta/tests.toml   |  0
 exercises/{ => practice}/acronym/Acronym.cs   |  0
 .../{ => practice}/acronym/Acronym.csproj     |  0
 .../{ => practice}/acronym/AcronymTests.cs    |  0
 exercises/{ => practice}/acronym/Example.cs   |  0
 exercises/{ => practice}/acronym/README.md    |  0
 .../affine-cipher/.editorconfig               |  0
 .../affine-cipher/.meta/tests.toml            |  0
 .../affine-cipher/AffineCipher.cs             |  0
 .../affine-cipher/AffineCipher.csproj         |  0
 .../affine-cipher/AffineCipherTests.cs        |  0
 .../{ => practice}/affine-cipher/Example.cs   |  0
 .../{ => practice}/affine-cipher/README.md    |  0
 .../all-your-base/.editorconfig               |  0
 .../all-your-base/.meta/tests.toml            |  0
 .../all-your-base/AllYourBase.cs              |  0
 .../all-your-base/AllYourBase.csproj          |  0
 .../all-your-base/AllYourBaseTests.cs         |  0
 .../{ => practice}/all-your-base/Example.cs   |  0
 .../{ => practice}/all-your-base/README.md    |  0
 .../{ => practice}/allergies/.editorconfig    |  0
 .../{ => practice}/allergies/.meta/hints.md   |  0
 .../{ => practice}/allergies/.meta/tests.toml |  0
 .../{ => practice}/allergies/Allergies.cs     |  0
 .../{ => practice}/allergies/Allergies.csproj |  0
 .../allergies/AllergiesTests.cs               |  0
 exercises/{ => practice}/allergies/Example.cs |  0
 exercises/{ => practice}/allergies/README.md  |  0
 .../{ => practice}/alphametics/.editorconfig  |  0
 .../{ => practice}/alphametics/.meta/hints.md |  0
 .../alphametics/.meta/tests.toml              |  0
 .../{ => practice}/alphametics/Alphametics.cs |  0
 .../alphametics/Alphametics.csproj            |  0
 .../alphametics/AlphameticsTests.cs           |  0
 .../{ => practice}/alphametics/Example.cs     |  0
 .../{ => practice}/alphametics/README.md      |  0
 .../{ => practice}/anagram/.editorconfig      |  0
 .../{ => practice}/anagram/.meta/tests.toml   |  0
 exercises/{ => practice}/anagram/Anagram.cs   |  0
 .../{ => practice}/anagram/Anagram.csproj     |  0
 .../{ => practice}/anagram/AnagramTests.cs    |  0
 exercises/{ => practice}/anagram/Example.cs   |  0
 exercises/{ => practice}/anagram/README.md    |  0
 .../armstrong-numbers/.editorconfig           |  0
 .../armstrong-numbers/.meta/tests.toml        |  0
 .../armstrong-numbers/ArmstrongNumbers.cs     |  0
 .../armstrong-numbers/ArmstrongNumbers.csproj |  0
 .../ArmstrongNumbersTests.cs                  |  0
 .../armstrong-numbers/Example.cs              |  0
 .../armstrong-numbers/README.md               |  0
 .../atbash-cipher/.editorconfig               |  0
 .../atbash-cipher/.meta/tests.toml            |  0
 .../atbash-cipher/AtbashCipher.cs             |  0
 .../atbash-cipher/AtbashCipher.csproj         |  0
 .../atbash-cipher/AtbashCipherTests.cs        |  0
 .../{ => practice}/atbash-cipher/Example.cs   |  0
 .../{ => practice}/atbash-cipher/README.md    |  0
 .../{ => practice}/bank-account/.editorconfig |  0
 .../bank-account/.meta/hints.md               |  0
 .../bank-account/BankAccount.cs               |  0
 .../bank-account/BankAccount.csproj           |  0
 .../bank-account/BankAccountTests.cs          |  0
 .../{ => practice}/bank-account/Example.cs    |  0
 .../{ => practice}/bank-account/README.md     |  0
 .../{ => practice}/beer-song/.editorconfig    |  0
 .../{ => practice}/beer-song/.meta/hints.md   |  0
 .../{ => practice}/beer-song/.meta/tests.toml |  0
 .../{ => practice}/beer-song/BeerSong.cs      |  0
 .../{ => practice}/beer-song/BeerSong.csproj  |  0
 .../{ => practice}/beer-song/BeerSongTests.cs |  0
 exercises/{ => practice}/beer-song/Example.cs |  0
 exercises/{ => practice}/beer-song/README.md  |  0
 .../binary-search-tree/.editorconfig          |  0
 .../binary-search-tree/.meta/tests.toml       |  0
 .../binary-search-tree/BinarySearchTree.cs    |  0
 .../BinarySearchTree.csproj                   |  0
 .../BinarySearchTreeTests.cs                  |  0
 .../binary-search-tree/Example.cs             |  0
 .../binary-search-tree/README.md              |  0
 .../binary-search/.editorconfig               |  0
 .../binary-search/.meta/tests.toml            |  0
 .../binary-search/BinarySearch.cs             |  0
 .../binary-search/BinarySearch.csproj         |  0
 .../binary-search/BinarySearchTests.cs        |  0
 .../{ => practice}/binary-search/Example.cs   |  0
 .../{ => practice}/binary-search/README.md    |  0
 exercises/{ => practice}/binary/.editorconfig |  0
 .../{ => practice}/binary/.meta/tests.toml    |  0
 exercises/{ => practice}/binary/Binary.cs     |  0
 exercises/{ => practice}/binary/Binary.csproj |  0
 .../{ => practice}/binary/BinaryTests.cs      |  0
 exercises/{ => practice}/binary/Example.cs    |  0
 exercises/{ => practice}/binary/README.md     |  0
 exercises/{ => practice}/bob/.editorconfig    |  0
 exercises/{ => practice}/bob/.meta/tests.toml |  0
 exercises/{ => practice}/bob/Bob.cs           |  0
 exercises/{ => practice}/bob/Bob.csproj       |  0
 exercises/{ => practice}/bob/BobTests.cs      |  0
 exercises/{ => practice}/bob/Example.cs       |  0
 exercises/{ => practice}/bob/README.md        |  0
 .../{ => practice}/book-store/.editorconfig   |  0
 .../book-store/.meta/tests.toml               |  0
 .../{ => practice}/book-store/BookStore.cs    |  0
 .../book-store/BookStore.csproj               |  0
 .../book-store/BookStoreTests.cs              |  0
 .../{ => practice}/book-store/Example.cs      |  0
 exercises/{ => practice}/book-store/README.md |  0
 .../{ => practice}/bowling/.editorconfig      |  0
 .../{ => practice}/bowling/.meta/tests.toml   |  0
 exercises/{ => practice}/bowling/Bowling.cs   |  0
 .../{ => practice}/bowling/Bowling.csproj     |  0
 .../{ => practice}/bowling/BowlingTests.cs    |  0
 exercises/{ => practice}/bowling/Example.cs   |  0
 exercises/{ => practice}/bowling/README.md    |  0
 exercises/{ => practice}/change/.editorconfig |  0
 .../{ => practice}/change/.meta/tests.toml    |  0
 exercises/{ => practice}/change/Change.cs     |  0
 exercises/{ => practice}/change/Change.csproj |  0
 .../{ => practice}/change/ChangeTests.cs      |  0
 exercises/{ => practice}/change/Example.cs    |  0
 exercises/{ => practice}/change/README.md     |  0
 .../circular-buffer/.editorconfig             |  0
 .../circular-buffer/.meta/tests.toml          |  0
 .../circular-buffer/CircularBuffer.cs         |  0
 .../circular-buffer/CircularBuffer.csproj     |  0
 .../circular-buffer/CircularBufferTests.cs    |  0
 .../{ => practice}/circular-buffer/Example.cs |  0
 .../{ => practice}/circular-buffer/README.md  |  0
 exercises/{ => practice}/clock/.editorconfig  |  0
 exercises/{ => practice}/clock/.meta/hints.md |  0
 .../{ => practice}/clock/.meta/tests.toml     |  0
 exercises/{ => practice}/clock/Clock.cs       |  0
 exercises/{ => practice}/clock/Clock.csproj   |  0
 exercises/{ => practice}/clock/ClockTests.cs  |  0
 exercises/{ => practice}/clock/Example.cs     |  0
 exercises/{ => practice}/clock/README.md      |  0
 .../collatz-conjecture/.editorconfig          |  0
 .../collatz-conjecture/.meta/tests.toml       |  0
 .../collatz-conjecture/CollatzConjecture.cs   |  0
 .../CollatzConjecture.csproj                  |  0
 .../CollatzConjectureTests.cs                 |  0
 .../collatz-conjecture/Example.cs             |  0
 .../collatz-conjecture/README.md              |  0
 .../complex-numbers/.editorconfig             |  0
 .../complex-numbers/.meta/tests.toml          |  0
 .../complex-numbers/ComplexNumbers.cs         |  0
 .../complex-numbers/ComplexNumbers.csproj     |  0
 .../complex-numbers/ComplexNumbersTests.cs    |  0
 .../{ => practice}/complex-numbers/Example.cs |  0
 .../{ => practice}/complex-numbers/README.md  |  0
 .../{ => practice}/connect/.editorconfig      |  0
 .../{ => practice}/connect/.meta/tests.toml   |  0
 exercises/{ => practice}/connect/Connect.cs   |  0
 .../{ => practice}/connect/Connect.csproj     |  0
 .../{ => practice}/connect/ConnectTests.cs    |  0
 exercises/{ => practice}/connect/Example.cs   |  0
 exercises/{ => practice}/connect/README.md    |  0
 .../crypto-square/.editorconfig               |  0
 .../crypto-square/.meta/tests.toml            |  0
 .../crypto-square/CryptoSquare.cs             |  0
 .../crypto-square/CryptoSquare.csproj         |  0
 .../crypto-square/CryptoSquareTests.cs        |  0
 .../{ => practice}/crypto-square/Example.cs   |  0
 .../{ => practice}/crypto-square/README.md    |  0
 .../{ => practice}/custom-set/.editorconfig   |  0
 .../{ => practice}/custom-set/.meta/hints.md  |  0
 .../custom-set/.meta/tests.toml               |  0
 .../{ => practice}/custom-set/CustomSet.cs    |  0
 .../custom-set/CustomSet.csproj               |  0
 .../custom-set/CustomSetTests.cs              |  0
 .../{ => practice}/custom-set/Example.cs      |  0
 exercises/{ => practice}/custom-set/README.md |  0
 exercises/{ => practice}/darts/.editorconfig  |  0
 .../{ => practice}/darts/.meta/tests.toml     |  0
 exercises/{ => practice}/darts/Darts.cs       |  0
 exercises/{ => practice}/darts/Darts.csproj   |  0
 exercises/{ => practice}/darts/DartsTests.cs  |  0
 exercises/{ => practice}/darts/Example.cs     |  0
 exercises/{ => practice}/darts/README.md      |  0
 .../{ => practice}/diamond/.editorconfig      |  0
 .../{ => practice}/diamond/.meta/hints.md     |  0
 .../{ => practice}/diamond/.meta/tests.toml   |  0
 exercises/{ => practice}/diamond/Diamond.cs   |  0
 .../{ => practice}/diamond/Diamond.csproj     |  0
 .../{ => practice}/diamond/DiamondTests.cs    |  0
 exercises/{ => practice}/diamond/Example.cs   |  0
 exercises/{ => practice}/diamond/README.md    |  0
 .../difference-of-squares/.editorconfig       |  0
 .../difference-of-squares/.meta/hints.md      |  0
 .../difference-of-squares/.meta/tests.toml    |  0
 .../DifferenceOfSquares.cs                    |  0
 .../DifferenceOfSquares.csproj                |  0
 .../DifferenceOfSquaresTests.cs               |  0
 .../difference-of-squares/Example.cs          |  0
 .../difference-of-squares/README.md           |  0
 .../diffie-hellman/.editorconfig              |  0
 .../diffie-hellman/.meta/hints.md             |  0
 .../diffie-hellman/.meta/tests.toml           |  0
 .../diffie-hellman/DiffieHellman.cs           |  0
 .../diffie-hellman/DiffieHellman.csproj       |  0
 .../diffie-hellman/DiffieHellmanTests.cs      |  0
 .../{ => practice}/diffie-hellman/Example.cs  |  0
 .../{ => practice}/diffie-hellman/README.md   |  0
 .../dnd-character/.editorconfig               |  0
 .../dnd-character/.meta/tests.toml            |  0
 .../dnd-character/DndCharacter.cs             |  0
 .../dnd-character/DndCharacter.csproj         |  0
 .../dnd-character/DndCharacterTests.cs        |  0
 .../{ => practice}/dnd-character/Example.cs   |  0
 .../{ => practice}/dnd-character/README.md    |  0
 .../{ => practice}/dominoes/.editorconfig     |  0
 .../{ => practice}/dominoes/.meta/tests.toml  |  0
 exercises/{ => practice}/dominoes/Dominoes.cs |  0
 .../{ => practice}/dominoes/Dominoes.csproj   |  0
 .../{ => practice}/dominoes/DominoesTests.cs  |  0
 exercises/{ => practice}/dominoes/Example.cs  |  0
 exercises/{ => practice}/dominoes/README.md   |  0
 .../{ => practice}/dot-dsl/.editorconfig      |  0
 .../{ => practice}/dot-dsl/.meta/hints.md     |  0
 exercises/{ => practice}/dot-dsl/DotDsl.cs    |  0
 .../{ => practice}/dot-dsl/DotDsl.csproj      |  0
 .../{ => practice}/dot-dsl/DotDslTests.cs     |  0
 exercises/{ => practice}/dot-dsl/Example.cs   |  0
 exercises/{ => practice}/dot-dsl/README.md    |  0
 .../error-handling/.editorconfig              |  0
 .../error-handling/ErrorHandling.cs           |  0
 .../error-handling/ErrorHandling.csproj       |  0
 .../error-handling/ErrorHandlingTests.cs      |  0
 .../{ => practice}/error-handling/Example.cs  |  0
 .../{ => practice}/error-handling/README.md   |  0
 exercises/{ => practice}/etl/.editorconfig    |  0
 exercises/{ => practice}/etl/.meta/tests.toml |  0
 exercises/{ => practice}/etl/Etl.cs           |  0
 exercises/{ => practice}/etl/Etl.csproj       |  0
 exercises/{ => practice}/etl/EtlTests.cs      |  0
 exercises/{ => practice}/etl/Example.cs       |  0
 exercises/{ => practice}/etl/README.md        |  0
 .../flatten-array/.editorconfig               |  0
 .../flatten-array/.meta/tests.toml            |  0
 .../{ => practice}/flatten-array/Example.cs   |  0
 .../flatten-array/FlattenArray.cs             |  0
 .../flatten-array/FlattenArray.csproj         |  0
 .../flatten-array/FlattenArrayTests.cs        |  0
 .../{ => practice}/flatten-array/README.md    |  0
 .../{ => practice}/food-chain/.editorconfig   |  0
 .../{ => practice}/food-chain/.meta/hints.md  |  0
 .../food-chain/.meta/tests.toml               |  0
 .../{ => practice}/food-chain/Example.cs      |  0
 .../{ => practice}/food-chain/FoodChain.cs    |  0
 .../food-chain/FoodChain.csproj               |  0
 .../food-chain/FoodChainTests.cs              |  0
 exercises/{ => practice}/food-chain/README.md |  0
 exercises/{ => practice}/forth/.editorconfig  |  0
 exercises/{ => practice}/forth/.meta/hints.md |  0
 .../{ => practice}/forth/.meta/tests.toml     |  0
 exercises/{ => practice}/forth/Example.cs     |  0
 exercises/{ => practice}/forth/Forth.cs       |  0
 exercises/{ => practice}/forth/Forth.csproj   |  0
 exercises/{ => practice}/forth/ForthTests.cs  |  0
 exercises/{ => practice}/forth/README.md      |  0
 .../{ => practice}/gigasecond/.editorconfig   |  0
 .../gigasecond/.meta/tests.toml               |  0
 .../{ => practice}/gigasecond/Example.cs      |  0
 .../{ => practice}/gigasecond/Gigasecond.cs   |  0
 .../gigasecond/Gigasecond.csproj              |  0
 .../gigasecond/GigasecondTests.cs             |  0
 exercises/{ => practice}/gigasecond/README.md |  0
 .../{ => practice}/go-counting/.editorconfig  |  0
 .../go-counting/.meta/tests.toml              |  0
 .../{ => practice}/go-counting/Example.cs     |  0
 .../{ => practice}/go-counting/GoCounting.cs  |  0
 .../go-counting/GoCounting.csproj             |  0
 .../go-counting/GoCountingTests.cs            |  0
 .../{ => practice}/go-counting/README.md      |  0
 .../{ => practice}/grade-school/.editorconfig |  0
 .../grade-school/.meta/tests.toml             |  0
 .../{ => practice}/grade-school/Example.cs    |  0
 .../grade-school/GradeSchool.cs               |  0
 .../grade-school/GradeSchool.csproj           |  0
 .../grade-school/GradeSchoolTests.cs          |  0
 .../{ => practice}/grade-school/README.md     |  0
 exercises/{ => practice}/grains/.editorconfig |  0
 .../{ => practice}/grains/.meta/tests.toml    |  0
 exercises/{ => practice}/grains/Example.cs    |  0
 exercises/{ => practice}/grains/Grains.cs     |  0
 exercises/{ => practice}/grains/Grains.csproj |  0
 .../{ => practice}/grains/GrainsTests.cs      |  0
 exercises/{ => practice}/grains/README.md     |  0
 exercises/{ => practice}/grep/.editorconfig   |  0
 .../{ => practice}/grep/.meta/tests.toml      |  0
 exercises/{ => practice}/grep/Example.cs      |  0
 exercises/{ => practice}/grep/Grep.cs         |  0
 exercises/{ => practice}/grep/Grep.csproj     |  0
 exercises/{ => practice}/grep/GrepTests.cs    |  0
 exercises/{ => practice}/grep/README.md       |  0
 .../{ => practice}/hamming/.editorconfig      |  0
 .../{ => practice}/hamming/.meta/tests.toml   |  0
 exercises/{ => practice}/hamming/Example.cs   |  0
 exercises/{ => practice}/hamming/Hamming.cs   |  0
 .../{ => practice}/hamming/Hamming.csproj     |  0
 .../{ => practice}/hamming/HammingTests.cs    |  0
 exercises/{ => practice}/hamming/README.md    |  0
 .../{ => practice}/hangman/.editorconfig      |  0
 .../{ => practice}/hangman/.meta/hints.md     |  0
 exercises/{ => practice}/hangman/Example.cs   |  0
 exercises/{ => practice}/hangman/Hangman.cs   |  0
 .../{ => practice}/hangman/Hangman.csproj     |  0
 .../{ => practice}/hangman/HangmanTests.cs    |  0
 exercises/{ => practice}/hangman/README.md    |  0
 .../{ => practice}/hello-world/.editorconfig  |  0
 .../hello-world/.meta/tests.toml              |  0
 .../{ => practice}/hello-world/Example.cs     |  0
 .../{ => practice}/hello-world/HelloWorld.cs  |  0
 .../hello-world/HelloWorld.csproj             |  0
 .../hello-world/HelloWorldTests.cs            |  0
 .../{ => practice}/hello-world/README.md      |  0
 .../{ => practice}/hexadecimal/.editorconfig  |  0
 .../{ => practice}/hexadecimal/Example.cs     |  0
 .../{ => practice}/hexadecimal/Hexadecimal.cs |  0
 .../hexadecimal/Hexadecimal.csproj            |  0
 .../hexadecimal/HexadecimalTests.cs           |  0
 .../{ => practice}/hexadecimal/README.md      |  0
 .../{ => practice}/high-scores/.editorconfig  |  0
 .../high-scores/.meta/tests.toml              |  0
 .../{ => practice}/high-scores/Example.cs     |  0
 .../{ => practice}/high-scores/HighScores.cs  |  0
 .../high-scores/HighScores.csproj             |  0
 .../high-scores/HighScoresTests.cs            |  0
 .../{ => practice}/high-scores/README.md      |  0
 exercises/{ => practice}/house/.editorconfig  |  0
 exercises/{ => practice}/house/.meta/hints.md |  0
 .../{ => practice}/house/.meta/tests.toml     |  0
 exercises/{ => practice}/house/Example.cs     |  0
 exercises/{ => practice}/house/House.cs       |  0
 exercises/{ => practice}/house/House.csproj   |  0
 exercises/{ => practice}/house/HouseTests.cs  |  0
 exercises/{ => practice}/house/README.md      |  0
 .../isbn-verifier/.editorconfig               |  0
 .../isbn-verifier/.meta/tests.toml            |  0
 .../{ => practice}/isbn-verifier/Example.cs   |  0
 .../isbn-verifier/IsbnVerifier.cs             |  0
 .../isbn-verifier/IsbnVerifier.csproj         |  0
 .../isbn-verifier/IsbnVerifierTests.cs        |  0
 .../{ => practice}/isbn-verifier/README.md    |  0
 .../{ => practice}/isogram/.editorconfig      |  0
 .../{ => practice}/isogram/.meta/tests.toml   |  0
 exercises/{ => practice}/isogram/Example.cs   |  0
 exercises/{ => practice}/isogram/Isogram.cs   |  0
 .../{ => practice}/isogram/Isogram.csproj     |  0
 .../{ => practice}/isogram/IsogramTests.cs    |  0
 exercises/{ => practice}/isogram/README.md    |  0
 .../kindergarten-garden/.editorconfig         |  0
 .../kindergarten-garden/.meta/tests.toml      |  0
 .../kindergarten-garden/Example.cs            |  0
 .../kindergarten-garden/KindergartenGarden.cs |  0
 .../KindergartenGarden.csproj                 |  0
 .../KindergartenGardenTests.cs                |  0
 .../kindergarten-garden/README.md             |  0
 .../largest-series-product/.editorconfig      |  0
 .../largest-series-product/.meta/tests.toml   |  0
 .../largest-series-product/Example.cs         | 66 +++++++++----------
 .../LargestSeriesProduct.cs                   |  0
 .../LargestSeriesProduct.csproj               |  0
 .../LargestSeriesProductTests.cs              |  0
 .../largest-series-product/README.md          |  0
 exercises/{ => practice}/leap/.editorconfig   |  0
 exercises/{ => practice}/leap/.meta/hints.md  |  0
 .../{ => practice}/leap/.meta/tests.toml      |  0
 exercises/{ => practice}/leap/Example.cs      |  0
 exercises/{ => practice}/leap/Leap.cs         |  0
 exercises/{ => practice}/leap/Leap.csproj     |  0
 exercises/{ => practice}/leap/LeapTests.cs    |  0
 exercises/{ => practice}/leap/README.md       |  0
 exercises/{ => practice}/ledger/.editorconfig |  0
 exercises/{ => practice}/ledger/Example.cs    |  0
 exercises/{ => practice}/ledger/Ledger.cs     |  0
 exercises/{ => practice}/ledger/Ledger.csproj |  0
 .../{ => practice}/ledger/LedgerTests.cs      |  0
 exercises/{ => practice}/ledger/README.md     |  0
 .../{ => practice}/linked-list/.editorconfig  |  0
 .../{ => practice}/linked-list/Example.cs     |  0
 .../{ => practice}/linked-list/LinkedList.cs  |  0
 .../linked-list/LinkedList.csproj             |  0
 .../linked-list/LinkedListTests.cs            |  0
 .../{ => practice}/linked-list/README.md      |  0
 .../{ => practice}/list-ops/.editorconfig     |  0
 .../{ => practice}/list-ops/.meta/hints.md    |  0
 .../{ => practice}/list-ops/.meta/tests.toml  |  0
 exercises/{ => practice}/list-ops/Example.cs  |  0
 exercises/{ => practice}/list-ops/ListOps.cs  |  0
 .../{ => practice}/list-ops/ListOps.csproj    |  0
 .../{ => practice}/list-ops/ListOpsTests.cs   |  0
 exercises/{ => practice}/list-ops/README.md   |  0
 exercises/{ => practice}/luhn/.editorconfig   |  0
 .../{ => practice}/luhn/.meta/tests.toml      |  0
 exercises/{ => practice}/luhn/Example.cs      |  0
 exercises/{ => practice}/luhn/Luhn.cs         |  0
 exercises/{ => practice}/luhn/Luhn.csproj     |  0
 exercises/{ => practice}/luhn/LuhnTests.cs    |  0
 exercises/{ => practice}/luhn/README.md       |  0
 .../{ => practice}/markdown/.editorconfig     |  0
 .../{ => practice}/markdown/.meta/hints.md    |  0
 .../{ => practice}/markdown/.meta/tests.toml  |  0
 exercises/{ => practice}/markdown/Example.cs  |  0
 exercises/{ => practice}/markdown/Markdown.cs |  0
 .../{ => practice}/markdown/Markdown.csproj   |  0
 .../{ => practice}/markdown/MarkdownTests.cs  |  0
 exercises/{ => practice}/markdown/README.md   |  0
 .../matching-brackets/.editorconfig           |  0
 .../matching-brackets/.meta/tests.toml        |  0
 .../matching-brackets/Example.cs              |  0
 .../matching-brackets/MatchingBrackets.cs     |  0
 .../matching-brackets/MatchingBrackets.csproj |  0
 .../MatchingBracketsTests.cs                  |  0
 .../matching-brackets/README.md               |  0
 exercises/{ => practice}/matrix/.editorconfig |  0
 .../{ => practice}/matrix/.meta/tests.toml    |  0
 exercises/{ => practice}/matrix/Example.cs    |  0
 exercises/{ => practice}/matrix/Matrix.cs     |  0
 exercises/{ => practice}/matrix/Matrix.csproj |  0
 .../{ => practice}/matrix/MatrixTests.cs      |  0
 exercises/{ => practice}/matrix/README.md     |  0
 exercises/{ => practice}/meetup/.editorconfig |  0
 .../{ => practice}/meetup/.meta/tests.toml    |  0
 exercises/{ => practice}/meetup/Example.cs    |  0
 exercises/{ => practice}/meetup/Meetup.cs     |  0
 exercises/{ => practice}/meetup/Meetup.csproj |  0
 .../{ => practice}/meetup/MeetupTests.cs      |  0
 exercises/{ => practice}/meetup/README.md     |  0
 .../{ => practice}/minesweeper/.editorconfig  |  0
 .../minesweeper/.meta/tests.toml              |  0
 .../{ => practice}/minesweeper/Example.cs     |  0
 .../{ => practice}/minesweeper/Minesweeper.cs |  0
 .../minesweeper/Minesweeper.csproj            |  0
 .../minesweeper/MinesweeperTests.cs           |  0
 .../{ => practice}/minesweeper/README.md      |  0
 .../{ => practice}/nth-prime/.editorconfig    |  0
 .../{ => practice}/nth-prime/.meta/hints.md   |  0
 .../{ => practice}/nth-prime/.meta/tests.toml |  0
 exercises/{ => practice}/nth-prime/Example.cs |  0
 .../{ => practice}/nth-prime/NthPrime.cs      |  0
 .../{ => practice}/nth-prime/NthPrime.csproj  |  0
 .../{ => practice}/nth-prime/NthPrimeTests.cs |  0
 exercises/{ => practice}/nth-prime/README.md  |  0
 .../nucleotide-count/.editorconfig            |  0
 .../nucleotide-count/.meta/hints.md           |  0
 .../nucleotide-count/.meta/tests.toml         |  0
 .../nucleotide-count/Example.cs               |  0
 .../nucleotide-count/NucleotideCount.cs       |  0
 .../nucleotide-count/NucleotideCount.csproj   |  0
 .../nucleotide-count/NucleotideCountTests.cs  |  0
 .../{ => practice}/nucleotide-count/README.md |  0
 .../{ => practice}/ocr-numbers/.editorconfig  |  0
 .../ocr-numbers/.meta/tests.toml              |  0
 .../{ => practice}/ocr-numbers/Example.cs     |  0
 .../{ => practice}/ocr-numbers/OcrNumbers.cs  |  0
 .../ocr-numbers/OcrNumbers.csproj             |  0
 .../ocr-numbers/OcrNumbersTests.cs            |  0
 .../{ => practice}/ocr-numbers/README.md      |  0
 exercises/{ => practice}/octal/.editorconfig  |  0
 exercises/{ => practice}/octal/Example.cs     |  0
 exercises/{ => practice}/octal/Octal.cs       |  0
 exercises/{ => practice}/octal/Octal.csproj   |  0
 exercises/{ => practice}/octal/OctalTests.cs  |  0
 exercises/{ => practice}/octal/README.md      |  0
 .../palindrome-products/.editorconfig         |  0
 .../palindrome-products/.meta/hints.md        |  0
 .../palindrome-products/.meta/tests.toml      |  0
 .../palindrome-products/Example.cs            |  0
 .../palindrome-products/PalindromeProducts.cs |  0
 .../PalindromeProducts.csproj                 |  0
 .../PalindromeProductsTests.cs                |  0
 .../palindrome-products/README.md             |  0
 .../{ => practice}/pangram/.editorconfig      |  0
 .../{ => practice}/pangram/.meta/tests.toml   |  0
 exercises/{ => practice}/pangram/Example.cs   |  0
 exercises/{ => practice}/pangram/Pangram.cs   |  0
 .../{ => practice}/pangram/Pangram.csproj     |  0
 .../{ => practice}/pangram/PangramTests.cs    |  0
 exercises/{ => practice}/pangram/README.md    |  0
 .../parallel-letter-frequency/.editorconfig   |  0
 .../parallel-letter-frequency/Example.cs      |  0
 .../ParallelLetterFrequency.cs                |  0
 .../ParallelLetterFrequency.csproj            |  0
 .../ParallelLetterFrequencyTests.cs           |  0
 .../parallel-letter-frequency/README.md       |  0
 .../pascals-triangle/.editorconfig            |  0
 .../pascals-triangle/.meta/tests.toml         |  0
 .../pascals-triangle/Example.cs               |  0
 .../pascals-triangle/PascalsTriangle.cs       |  0
 .../pascals-triangle/PascalsTriangle.csproj   |  0
 .../pascals-triangle/PascalsTriangleTests.cs  |  0
 .../{ => practice}/pascals-triangle/README.md |  0
 .../perfect-numbers/.editorconfig             |  0
 .../perfect-numbers/.meta/tests.toml          |  0
 .../{ => practice}/perfect-numbers/Example.cs |  0
 .../perfect-numbers/PerfectNumbers.cs         |  0
 .../perfect-numbers/PerfectNumbers.csproj     |  0
 .../perfect-numbers/PerfectNumbersTests.cs    |  0
 .../{ => practice}/perfect-numbers/README.md  |  0
 .../{ => practice}/phone-number/.editorconfig |  0
 .../phone-number/.meta/tests.toml             |  0
 .../{ => practice}/phone-number/Example.cs    |  0
 .../phone-number/PhoneNumber.cs               |  0
 .../phone-number/PhoneNumber.csproj           |  0
 .../phone-number/PhoneNumberTests.cs          |  0
 .../{ => practice}/phone-number/README.md     |  0
 .../{ => practice}/pig-latin/.editorconfig    |  0
 .../{ => practice}/pig-latin/.meta/tests.toml |  0
 exercises/{ => practice}/pig-latin/Example.cs |  0
 .../{ => practice}/pig-latin/PigLatin.cs      |  0
 .../{ => practice}/pig-latin/PigLatin.csproj  |  0
 .../{ => practice}/pig-latin/PigLatinTests.cs |  0
 exercises/{ => practice}/pig-latin/README.md  |  0
 exercises/{ => practice}/poker/.editorconfig  |  0
 .../{ => practice}/poker/.meta/tests.toml     |  0
 exercises/{ => practice}/poker/Example.cs     |  0
 exercises/{ => practice}/poker/Poker.cs       |  0
 exercises/{ => practice}/poker/Poker.csproj   |  0
 exercises/{ => practice}/poker/PokerTests.cs  |  0
 exercises/{ => practice}/poker/README.md      |  0
 exercises/{ => practice}/pov/.editorconfig    |  0
 exercises/{ => practice}/pov/.meta/tests.toml |  0
 exercises/{ => practice}/pov/Example.cs       |  0
 exercises/{ => practice}/pov/Pov.cs           |  0
 exercises/{ => practice}/pov/Pov.csproj       |  0
 exercises/{ => practice}/pov/PovTests.cs      |  0
 exercises/{ => practice}/pov/README.md        |  0
 .../prime-factors/.editorconfig               |  0
 .../prime-factors/.meta/tests.toml            |  0
 .../{ => practice}/prime-factors/Example.cs   |  0
 .../prime-factors/PrimeFactors.cs             |  0
 .../prime-factors/PrimeFactors.csproj         |  0
 .../prime-factors/PrimeFactorsTests.cs        |  0
 .../{ => practice}/prime-factors/README.md    |  0
 .../protein-translation/.editorconfig         |  0
 .../protein-translation/.meta/tests.toml      |  0
 .../protein-translation/Example.cs            |  0
 .../protein-translation/ProteinTranslation.cs |  0
 .../ProteinTranslation.csproj                 |  0
 .../ProteinTranslationTests.cs                |  0
 .../protein-translation/README.md             |  0
 .../{ => practice}/proverb/.editorconfig      |  0
 .../{ => practice}/proverb/.meta/hints.md     |  0
 .../{ => practice}/proverb/.meta/tests.toml   |  0
 exercises/{ => practice}/proverb/Example.cs   |  0
 exercises/{ => practice}/proverb/Proverb.cs   |  0
 .../{ => practice}/proverb/Proverb.csproj     |  0
 .../{ => practice}/proverb/ProverbTests.cs    |  0
 exercises/{ => practice}/proverb/README.md    |  0
 .../pythagorean-triplet/.editorconfig         |  0
 .../pythagorean-triplet/.meta/tests.toml      |  0
 .../pythagorean-triplet/Example.cs            |  0
 .../pythagorean-triplet/PythagoreanTriplet.cs |  0
 .../PythagoreanTriplet.csproj                 |  0
 .../PythagoreanTripletTests.cs                |  0
 .../pythagorean-triplet/README.md             |  0
 .../{ => practice}/queen-attack/.editorconfig |  0
 .../queen-attack/.meta/tests.toml             |  0
 .../{ => practice}/queen-attack/Example.cs    |  0
 .../queen-attack/QueenAttack.cs               |  0
 .../queen-attack/QueenAttack.csproj           |  0
 .../queen-attack/QueenAttackTests.cs          |  0
 .../{ => practice}/queen-attack/README.md     |  0
 .../rail-fence-cipher/.editorconfig           |  0
 .../rail-fence-cipher/.meta/tests.toml        |  0
 .../rail-fence-cipher/Example.cs              |  0
 .../rail-fence-cipher/README.md               |  0
 .../rail-fence-cipher/RailFenceCipher.cs      |  0
 .../rail-fence-cipher/RailFenceCipher.csproj  |  0
 .../rail-fence-cipher/RailFenceCipherTests.cs |  0
 .../{ => practice}/raindrops/.editorconfig    |  0
 .../{ => practice}/raindrops/.meta/tests.toml |  0
 exercises/{ => practice}/raindrops/Example.cs |  0
 exercises/{ => practice}/raindrops/README.md  |  0
 .../{ => practice}/raindrops/Raindrops.cs     |  0
 .../{ => practice}/raindrops/Raindrops.csproj |  0
 .../raindrops/RaindropsTests.cs               |  0
 .../rational-numbers/.editorconfig            |  0
 .../rational-numbers/.meta/tests.toml         |  0
 .../rational-numbers/Example.cs               |  0
 .../{ => practice}/rational-numbers/README.md |  0
 .../rational-numbers/RationalNumbers.cs       |  0
 .../rational-numbers/RationalNumbers.csproj   |  0
 .../rational-numbers/RationalNumbersTests.cs  |  0
 .../{ => practice}/rational-numbers/hints.md  |  0
 exercises/{ => practice}/react/.editorconfig  |  0
 exercises/{ => practice}/react/.meta/hints.md |  0
 .../{ => practice}/react/.meta/tests.toml     |  0
 exercises/{ => practice}/react/Example.cs     |  0
 exercises/{ => practice}/react/README.md      |  0
 exercises/{ => practice}/react/React.cs       |  0
 exercises/{ => practice}/react/React.csproj   |  0
 exercises/{ => practice}/react/ReactTests.cs  |  0
 .../{ => practice}/rectangles/.editorconfig   |  0
 .../rectangles/.meta/tests.toml               |  0
 .../{ => practice}/rectangles/Example.cs      |  0
 exercises/{ => practice}/rectangles/README.md |  0
 .../{ => practice}/rectangles/Rectangles.cs   |  0
 .../rectangles/Rectangles.csproj              |  0
 .../rectangles/RectanglesTests.cs             |  0
 .../resistor-color-duo/.editorconfig          |  0
 .../resistor-color-duo/.meta/tests.toml       |  0
 .../resistor-color-duo/Example.cs             |  0
 .../resistor-color-duo/README.md              |  0
 .../resistor-color-duo/ResistorColorDuo.cs    |  0
 .../ResistorColorDuo.csproj                   |  0
 .../ResistorColorDuoTests.cs                  |  0
 .../resistor-color-trio/.editorconfig         |  0
 .../resistor-color-trio/.meta/tests.toml      |  0
 .../resistor-color-trio/Example.cs            |  0
 .../resistor-color-trio/README.md             |  0
 .../resistor-color-trio/ResistorColorTrio.cs  |  0
 .../ResistorColorTrio.csproj                  |  0
 .../ResistorColorTrioTests.cs                 |  0
 .../resistor-color/.editorconfig              |  0
 .../resistor-color/.meta/tests.toml           |  0
 .../{ => practice}/resistor-color/Example.cs  |  0
 .../{ => practice}/resistor-color/README.md   |  0
 .../resistor-color/ResistorColor.cs           |  0
 .../resistor-color/ResistorColor.csproj       |  0
 .../resistor-color/ResistorColorTests.cs      |  0
 .../{ => practice}/rest-api/.editorconfig     |  0
 .../{ => practice}/rest-api/.meta/tests.toml  |  0
 exercises/{ => practice}/rest-api/Example.cs  |  0
 exercises/{ => practice}/rest-api/README.md   |  0
 exercises/{ => practice}/rest-api/RestApi.cs  |  0
 .../{ => practice}/rest-api/RestApi.csproj    |  0
 .../{ => practice}/rest-api/RestApiTests.cs   |  0
 .../reverse-string/.editorconfig              |  0
 .../reverse-string/.meta/tests.toml           |  0
 .../{ => practice}/reverse-string/Example.cs  |  0
 .../{ => practice}/reverse-string/README.md   |  0
 .../reverse-string/ReverseString.cs           |  0
 .../reverse-string/ReverseString.csproj       |  0
 .../reverse-string/ReverseStringTests.cs      |  0
 .../rna-transcription/.editorconfig           |  0
 .../rna-transcription/.meta/tests.toml        |  0
 .../rna-transcription/Example.cs              |  0
 .../rna-transcription/README.md               |  0
 .../rna-transcription/RnaTranscription.cs     |  0
 .../rna-transcription/RnaTranscription.csproj |  0
 .../RnaTranscriptionTests.cs                  |  0
 .../{ => practice}/robot-name/.editorconfig   |  0
 .../{ => practice}/robot-name/Example.cs      |  0
 exercises/{ => practice}/robot-name/README.md |  0
 .../{ => practice}/robot-name/RobotName.cs    |  0
 .../robot-name/RobotName.csproj               |  0
 .../robot-name/RobotNameTests.cs              |  0
 .../robot-simulator/.editorconfig             |  0
 .../robot-simulator/.meta/tests.toml          |  0
 .../{ => practice}/robot-simulator/Example.cs |  0
 .../{ => practice}/robot-simulator/README.md  |  0
 .../robot-simulator/RobotSimulator.cs         |  0
 .../robot-simulator/RobotSimulator.csproj     |  0
 .../robot-simulator/RobotSimulatorTests.cs    |  0
 .../roman-numerals/.editorconfig              |  0
 .../roman-numerals/.meta/hints.md             |  0
 .../roman-numerals/.meta/tests.toml           |  0
 .../{ => practice}/roman-numerals/Example.cs  |  0
 .../{ => practice}/roman-numerals/README.md   |  0
 .../roman-numerals/RomanNumerals.cs           |  0
 .../roman-numerals/RomanNumerals.csproj       |  0
 .../roman-numerals/RomanNumeralsTests.cs      |  0
 .../rotational-cipher/.editorconfig           |  0
 .../rotational-cipher/.meta/tests.toml        |  0
 .../rotational-cipher/Example.cs              |  0
 .../rotational-cipher/README.md               |  0
 .../rotational-cipher/RotationalCipher.cs     |  0
 .../rotational-cipher/RotationalCipher.csproj |  0
 .../RotationalCipherTests.cs                  |  0
 .../run-length-encoding/.editorconfig         |  0
 .../run-length-encoding/.meta/tests.toml      |  0
 .../run-length-encoding/Example.cs            |  0
 .../run-length-encoding/README.md             |  0
 .../run-length-encoding/RunLengthEncoding.cs  |  0
 .../RunLengthEncoding.csproj                  |  0
 .../RunLengthEncodingTests.cs                 |  0
 .../saddle-points/.editorconfig               |  0
 .../saddle-points/.meta/hints.md              |  0
 .../saddle-points/.meta/tests.toml            |  0
 .../{ => practice}/saddle-points/Example.cs   |  0
 .../{ => practice}/saddle-points/README.md    |  0
 .../saddle-points/SaddlePoints.cs             |  0
 .../saddle-points/SaddlePoints.csproj         |  0
 .../saddle-points/SaddlePointsTests.cs        |  0
 exercises/{ => practice}/say/.editorconfig    |  0
 exercises/{ => practice}/say/.meta/tests.toml |  0
 exercises/{ => practice}/say/Example.cs       |  0
 exercises/{ => practice}/say/README.md        |  0
 exercises/{ => practice}/say/Say.cs           |  0
 exercises/{ => practice}/say/Say.csproj       |  0
 exercises/{ => practice}/say/SayTests.cs      |  0
 .../scale-generator/.editorconfig             |  0
 .../scale-generator/.meta/tests.toml          |  0
 .../{ => practice}/scale-generator/Example.cs |  0
 .../{ => practice}/scale-generator/README.md  |  0
 .../scale-generator/ScaleGenerator.cs         |  0
 .../scale-generator/ScaleGenerator.csproj     |  0
 .../scale-generator/ScaleGeneratorTests.cs    |  0
 .../scrabble-score/.editorconfig              |  0
 .../scrabble-score/.meta/tests.toml           |  0
 .../{ => practice}/scrabble-score/Example.cs  |  0
 .../{ => practice}/scrabble-score/README.md   |  0
 .../scrabble-score/ScrabbleScore.cs           |  0
 .../scrabble-score/ScrabbleScore.csproj       |  0
 .../scrabble-score/ScrabbleScoreTests.cs      |  0
 .../secret-handshake/.editorconfig            |  0
 .../secret-handshake/.meta/tests.toml         |  0
 .../secret-handshake/Example.cs               |  0
 .../{ => practice}/secret-handshake/README.md |  0
 .../secret-handshake/SecretHandshake.cs       |  0
 .../secret-handshake/SecretHandshake.csproj   |  0
 .../secret-handshake/SecretHandshakeTests.cs  |  0
 exercises/{ => practice}/series/.editorconfig |  0
 .../{ => practice}/series/.meta/tests.toml    |  0
 exercises/{ => practice}/series/Example.cs    |  0
 exercises/{ => practice}/series/README.md     |  0
 exercises/{ => practice}/series/Series.cs     |  0
 exercises/{ => practice}/series/Series.csproj |  0
 .../{ => practice}/series/SeriesTests.cs      |  0
 .../{ => practice}/sgf-parsing/.editorconfig  |  0
 .../{ => practice}/sgf-parsing/.meta/hints.md |  0
 .../sgf-parsing/.meta/tests.toml              |  0
 .../{ => practice}/sgf-parsing/Example.cs     |  0
 .../{ => practice}/sgf-parsing/README.md      |  0
 .../{ => practice}/sgf-parsing/SgfParsing.cs  |  0
 .../sgf-parsing/SgfParsing.csproj             |  0
 .../sgf-parsing/SgfParsingTests.cs            |  0
 exercises/{ => practice}/sieve/.editorconfig  |  0
 .../{ => practice}/sieve/.meta/tests.toml     |  0
 exercises/{ => practice}/sieve/Example.cs     |  0
 exercises/{ => practice}/sieve/README.md      |  0
 exercises/{ => practice}/sieve/Sieve.cs       |  0
 exercises/{ => practice}/sieve/Sieve.csproj   |  0
 exercises/{ => practice}/sieve/SieveTests.cs  |  0
 .../simple-cipher/.editorconfig               |  0
 .../simple-cipher/.meta/tests.toml            |  0
 .../{ => practice}/simple-cipher/Example.cs   |  0
 .../{ => practice}/simple-cipher/README.md    |  0
 .../simple-cipher/SimpleCipher.cs             |  0
 .../simple-cipher/SimpleCipher.csproj         |  0
 .../simple-cipher/SimpleCipherTests.cs        |  0
 .../simple-linked-list/.editorconfig          |  0
 .../simple-linked-list/.meta/hints.md         |  0
 .../simple-linked-list/Example.cs             |  0
 .../simple-linked-list/README.md              |  0
 .../simple-linked-list/SimpleLinkedList.cs    |  0
 .../SimpleLinkedList.csproj                   |  0
 .../SimpleLinkedListTests.cs                  |  0
 .../{ => practice}/space-age/.editorconfig    |  0
 .../{ => practice}/space-age/.meta/tests.toml |  0
 exercises/{ => practice}/space-age/Example.cs |  0
 exercises/{ => practice}/space-age/README.md  |  0
 .../{ => practice}/space-age/SpaceAge.cs      |  0
 .../{ => practice}/space-age/SpaceAge.csproj  |  0
 .../{ => practice}/space-age/SpaceAgeTests.cs |  0
 .../spiral-matrix/.editorconfig               |  0
 .../spiral-matrix/.meta/tests.toml            |  0
 .../{ => practice}/spiral-matrix/Example.cs   |  0
 .../{ => practice}/spiral-matrix/README.md    |  0
 .../spiral-matrix/SpiralMatrix.cs             |  0
 .../spiral-matrix/SpiralMatrix.csproj         |  0
 .../spiral-matrix/SpiralMatrixTests.cs        |  0
 exercises/{ => practice}/strain/.editorconfig |  0
 exercises/{ => practice}/strain/Example.cs    |  0
 exercises/{ => practice}/strain/README.md     |  0
 exercises/{ => practice}/strain/Strain.cs     |  0
 exercises/{ => practice}/strain/Strain.csproj |  0
 .../{ => practice}/strain/StrainTests.cs      |  0
 .../{ => practice}/sublist/.editorconfig      |  0
 .../{ => practice}/sublist/.meta/hints.md     |  0
 .../{ => practice}/sublist/.meta/tests.toml   |  0
 exercises/{ => practice}/sublist/Example.cs   |  0
 exercises/{ => practice}/sublist/README.md    |  0
 exercises/{ => practice}/sublist/Sublist.cs   |  0
 .../{ => practice}/sublist/Sublist.csproj     |  0
 .../{ => practice}/sublist/SublistTests.cs    |  0
 .../sum-of-multiples/.editorconfig            |  0
 .../sum-of-multiples/.meta/hints.md           |  0
 .../sum-of-multiples/.meta/tests.toml         |  0
 .../sum-of-multiples/Example.cs               |  0
 .../{ => practice}/sum-of-multiples/README.md |  0
 .../sum-of-multiples/SumOfMultiples.cs        |  0
 .../sum-of-multiples/SumOfMultiples.csproj    |  0
 .../sum-of-multiples/SumOfMultiplesTests.cs   |  0
 .../{ => practice}/tournament/.editorconfig   |  0
 .../tournament/.meta/tests.toml               |  0
 .../{ => practice}/tournament/Example.cs      |  0
 exercises/{ => practice}/tournament/README.md |  0
 .../{ => practice}/tournament/Tournament.cs   |  0
 .../tournament/Tournament.csproj              |  0
 .../tournament/TournamentTests.cs             |  0
 .../{ => practice}/transpose/.editorconfig    |  0
 .../{ => practice}/transpose/.meta/tests.toml |  0
 exercises/{ => practice}/transpose/Example.cs |  0
 exercises/{ => practice}/transpose/README.md  |  0
 .../{ => practice}/transpose/Transpose.cs     |  0
 .../{ => practice}/transpose/Transpose.csproj |  0
 .../transpose/TransposeTests.cs               |  0
 .../tree-building/.editorconfig               |  0
 .../{ => practice}/tree-building/Example.cs   |  0
 .../{ => practice}/tree-building/README.md    |  0
 .../tree-building/TreeBuilding.cs             |  0
 .../tree-building/TreeBuilding.csproj         |  0
 .../tree-building/TreeBuildingTests.cs        |  0
 .../{ => practice}/triangle/.editorconfig     |  0
 .../{ => practice}/triangle/.meta/tests.toml  |  0
 exercises/{ => practice}/triangle/Example.cs  |  0
 exercises/{ => practice}/triangle/README.md   |  0
 exercises/{ => practice}/triangle/Triangle.cs |  0
 .../{ => practice}/triangle/Triangle.csproj   |  0
 .../{ => practice}/triangle/TriangleTests.cs  |  0
 .../{ => practice}/trinary/.editorconfig      |  0
 .../{ => practice}/trinary/.meta/tests.toml   |  0
 exercises/{ => practice}/trinary/Example.cs   |  0
 exercises/{ => practice}/trinary/README.md    |  0
 exercises/{ => practice}/trinary/Trinary.cs   |  0
 .../{ => practice}/trinary/Trinary.csproj     |  0
 .../{ => practice}/trinary/TrinaryTests.cs    |  0
 .../{ => practice}/twelve-days/.editorconfig  |  0
 .../{ => practice}/twelve-days/.meta/hints.md |  0
 .../twelve-days/.meta/tests.toml              |  0
 .../{ => practice}/twelve-days/Example.cs     |  0
 .../{ => practice}/twelve-days/README.md      |  0
 .../{ => practice}/twelve-days/TwelveDays.cs  |  0
 .../twelve-days/TwelveDays.csproj             |  0
 .../twelve-days/TwelveDaysTests.cs            |  0
 .../{ => practice}/two-bucket/.editorconfig   |  0
 .../two-bucket/.meta/tests.toml               |  0
 .../{ => practice}/two-bucket/Example.cs      |  0
 exercises/{ => practice}/two-bucket/README.md |  0
 .../{ => practice}/two-bucket/TwoBucket.cs    |  0
 .../two-bucket/TwoBucket.csproj               |  0
 .../two-bucket/TwoBucketTests.cs              |  0
 .../{ => practice}/two-fer/.editorconfig      |  0
 .../{ => practice}/two-fer/.meta/tests.toml   |  0
 exercises/{ => practice}/two-fer/Example.cs   |  0
 exercises/{ => practice}/two-fer/README.md    |  0
 exercises/{ => practice}/two-fer/TwoFer.cs    |  0
 .../{ => practice}/two-fer/TwoFer.csproj      |  0
 .../{ => practice}/two-fer/TwoFerTests.cs     |  0
 .../variable-length-quantity/.editorconfig    |  0
 .../variable-length-quantity/.meta/hints.md   |  0
 .../variable-length-quantity/.meta/tests.toml |  0
 .../variable-length-quantity/Example.cs       |  0
 .../variable-length-quantity/README.md        |  0
 .../VariableLengthQuantity.cs                 |  0
 .../VariableLengthQuantity.csproj             |  0
 .../VariableLengthQuantityTests.cs            |  0
 .../{ => practice}/word-count/.editorconfig   |  0
 .../word-count/.meta/tests.toml               |  0
 .../{ => practice}/word-count/Example.cs      |  0
 exercises/{ => practice}/word-count/README.md |  0
 .../{ => practice}/word-count/WordCount.cs    |  0
 .../word-count/WordCount.csproj               |  0
 .../word-count/WordCountTests.cs              |  0
 .../{ => practice}/word-search/.editorconfig  |  0
 .../{ => practice}/word-search/.meta/hints.md |  0
 .../word-search/.meta/tests.toml              |  0
 .../{ => practice}/word-search/Example.cs     |  0
 .../{ => practice}/word-search/README.md      |  0
 .../{ => practice}/word-search/WordSearch.cs  |  0
 .../word-search/WordSearch.csproj             |  0
 .../word-search/WordSearchTests.cs            |  0
 exercises/{ => practice}/wordy/.editorconfig  |  0
 exercises/{ => practice}/wordy/.meta/hints.md |  0
 .../{ => practice}/wordy/.meta/tests.toml     |  0
 exercises/{ => practice}/wordy/Example.cs     |  0
 exercises/{ => practice}/wordy/README.md      |  0
 exercises/{ => practice}/wordy/Wordy.cs       |  0
 exercises/{ => practice}/wordy/Wordy.csproj   |  0
 exercises/{ => practice}/wordy/WordyTests.cs  |  0
 exercises/{ => practice}/yacht/.editorconfig  |  0
 .../{ => practice}/yacht/.meta/tests.toml     |  0
 exercises/{ => practice}/yacht/Example.cs     |  0
 exercises/{ => practice}/yacht/README.md      |  0
 exercises/{ => practice}/yacht/Yacht.cs       |  0
 exercises/{ => practice}/yacht/Yacht.csproj   |  0
 exercises/{ => practice}/yacht/YachtTests.cs  |  0
 .../{ => practice}/zebra-puzzle/.editorconfig |  0
 .../zebra-puzzle/.meta/hints.md               |  0
 .../zebra-puzzle/.meta/tests.toml             |  0
 .../{ => practice}/zebra-puzzle/Example.cs    |  0
 .../{ => practice}/zebra-puzzle/README.md     |  0
 .../zebra-puzzle/ZebraPuzzle.cs               |  0
 .../zebra-puzzle/ZebraPuzzle.csproj           |  0
 .../zebra-puzzle/ZebraPuzzleTests.cs          |  0
 exercises/{ => practice}/zipper/.editorconfig |  0
 .../{ => practice}/zipper/.meta/hints.md      |  0
 .../{ => practice}/zipper/.meta/tests.toml    |  0
 exercises/{ => practice}/zipper/Example.cs    |  0
 exercises/{ => practice}/zipper/README.md     |  0
 exercises/{ => practice}/zipper/Zipper.cs     |  0
 exercises/{ => practice}/zipper/Zipper.csproj |  0
 .../{ => practice}/zipper/ZipperTests.cs      |  0
 904 files changed, 33 insertions(+), 33 deletions(-)
 rename exercises/{ => practice}/accumulate/.editorconfig (100%)
 rename exercises/{ => practice}/accumulate/.meta/hints.md (100%)
 rename exercises/{ => practice}/accumulate/Accumulate.cs (100%)
 rename exercises/{ => practice}/accumulate/Accumulate.csproj (100%)
 rename exercises/{ => practice}/accumulate/AccumulateTests.cs (100%)
 rename exercises/{ => practice}/accumulate/Example.cs (100%)
 rename exercises/{ => practice}/accumulate/README.md (100%)
 rename exercises/{ => practice}/acronym/.editorconfig (100%)
 rename exercises/{ => practice}/acronym/.meta/tests.toml (100%)
 rename exercises/{ => practice}/acronym/Acronym.cs (100%)
 rename exercises/{ => practice}/acronym/Acronym.csproj (100%)
 rename exercises/{ => practice}/acronym/AcronymTests.cs (100%)
 rename exercises/{ => practice}/acronym/Example.cs (100%)
 rename exercises/{ => practice}/acronym/README.md (100%)
 rename exercises/{ => practice}/affine-cipher/.editorconfig (100%)
 rename exercises/{ => practice}/affine-cipher/.meta/tests.toml (100%)
 rename exercises/{ => practice}/affine-cipher/AffineCipher.cs (100%)
 rename exercises/{ => practice}/affine-cipher/AffineCipher.csproj (100%)
 rename exercises/{ => practice}/affine-cipher/AffineCipherTests.cs (100%)
 rename exercises/{ => practice}/affine-cipher/Example.cs (100%)
 rename exercises/{ => practice}/affine-cipher/README.md (100%)
 rename exercises/{ => practice}/all-your-base/.editorconfig (100%)
 rename exercises/{ => practice}/all-your-base/.meta/tests.toml (100%)
 rename exercises/{ => practice}/all-your-base/AllYourBase.cs (100%)
 rename exercises/{ => practice}/all-your-base/AllYourBase.csproj (100%)
 rename exercises/{ => practice}/all-your-base/AllYourBaseTests.cs (100%)
 rename exercises/{ => practice}/all-your-base/Example.cs (100%)
 rename exercises/{ => practice}/all-your-base/README.md (100%)
 rename exercises/{ => practice}/allergies/.editorconfig (100%)
 rename exercises/{ => practice}/allergies/.meta/hints.md (100%)
 rename exercises/{ => practice}/allergies/.meta/tests.toml (100%)
 rename exercises/{ => practice}/allergies/Allergies.cs (100%)
 rename exercises/{ => practice}/allergies/Allergies.csproj (100%)
 rename exercises/{ => practice}/allergies/AllergiesTests.cs (100%)
 rename exercises/{ => practice}/allergies/Example.cs (100%)
 rename exercises/{ => practice}/allergies/README.md (100%)
 rename exercises/{ => practice}/alphametics/.editorconfig (100%)
 rename exercises/{ => practice}/alphametics/.meta/hints.md (100%)
 rename exercises/{ => practice}/alphametics/.meta/tests.toml (100%)
 rename exercises/{ => practice}/alphametics/Alphametics.cs (100%)
 rename exercises/{ => practice}/alphametics/Alphametics.csproj (100%)
 rename exercises/{ => practice}/alphametics/AlphameticsTests.cs (100%)
 rename exercises/{ => practice}/alphametics/Example.cs (100%)
 rename exercises/{ => practice}/alphametics/README.md (100%)
 rename exercises/{ => practice}/anagram/.editorconfig (100%)
 rename exercises/{ => practice}/anagram/.meta/tests.toml (100%)
 rename exercises/{ => practice}/anagram/Anagram.cs (100%)
 rename exercises/{ => practice}/anagram/Anagram.csproj (100%)
 rename exercises/{ => practice}/anagram/AnagramTests.cs (100%)
 rename exercises/{ => practice}/anagram/Example.cs (100%)
 rename exercises/{ => practice}/anagram/README.md (100%)
 rename exercises/{ => practice}/armstrong-numbers/.editorconfig (100%)
 rename exercises/{ => practice}/armstrong-numbers/.meta/tests.toml (100%)
 rename exercises/{ => practice}/armstrong-numbers/ArmstrongNumbers.cs (100%)
 rename exercises/{ => practice}/armstrong-numbers/ArmstrongNumbers.csproj (100%)
 rename exercises/{ => practice}/armstrong-numbers/ArmstrongNumbersTests.cs (100%)
 rename exercises/{ => practice}/armstrong-numbers/Example.cs (100%)
 rename exercises/{ => practice}/armstrong-numbers/README.md (100%)
 rename exercises/{ => practice}/atbash-cipher/.editorconfig (100%)
 rename exercises/{ => practice}/atbash-cipher/.meta/tests.toml (100%)
 rename exercises/{ => practice}/atbash-cipher/AtbashCipher.cs (100%)
 rename exercises/{ => practice}/atbash-cipher/AtbashCipher.csproj (100%)
 rename exercises/{ => practice}/atbash-cipher/AtbashCipherTests.cs (100%)
 rename exercises/{ => practice}/atbash-cipher/Example.cs (100%)
 rename exercises/{ => practice}/atbash-cipher/README.md (100%)
 rename exercises/{ => practice}/bank-account/.editorconfig (100%)
 rename exercises/{ => practice}/bank-account/.meta/hints.md (100%)
 rename exercises/{ => practice}/bank-account/BankAccount.cs (100%)
 rename exercises/{ => practice}/bank-account/BankAccount.csproj (100%)
 rename exercises/{ => practice}/bank-account/BankAccountTests.cs (100%)
 rename exercises/{ => practice}/bank-account/Example.cs (100%)
 rename exercises/{ => practice}/bank-account/README.md (100%)
 rename exercises/{ => practice}/beer-song/.editorconfig (100%)
 rename exercises/{ => practice}/beer-song/.meta/hints.md (100%)
 rename exercises/{ => practice}/beer-song/.meta/tests.toml (100%)
 rename exercises/{ => practice}/beer-song/BeerSong.cs (100%)
 rename exercises/{ => practice}/beer-song/BeerSong.csproj (100%)
 rename exercises/{ => practice}/beer-song/BeerSongTests.cs (100%)
 rename exercises/{ => practice}/beer-song/Example.cs (100%)
 rename exercises/{ => practice}/beer-song/README.md (100%)
 rename exercises/{ => practice}/binary-search-tree/.editorconfig (100%)
 rename exercises/{ => practice}/binary-search-tree/.meta/tests.toml (100%)
 rename exercises/{ => practice}/binary-search-tree/BinarySearchTree.cs (100%)
 rename exercises/{ => practice}/binary-search-tree/BinarySearchTree.csproj (100%)
 rename exercises/{ => practice}/binary-search-tree/BinarySearchTreeTests.cs (100%)
 rename exercises/{ => practice}/binary-search-tree/Example.cs (100%)
 rename exercises/{ => practice}/binary-search-tree/README.md (100%)
 rename exercises/{ => practice}/binary-search/.editorconfig (100%)
 rename exercises/{ => practice}/binary-search/.meta/tests.toml (100%)
 rename exercises/{ => practice}/binary-search/BinarySearch.cs (100%)
 rename exercises/{ => practice}/binary-search/BinarySearch.csproj (100%)
 rename exercises/{ => practice}/binary-search/BinarySearchTests.cs (100%)
 rename exercises/{ => practice}/binary-search/Example.cs (100%)
 rename exercises/{ => practice}/binary-search/README.md (100%)
 rename exercises/{ => practice}/binary/.editorconfig (100%)
 rename exercises/{ => practice}/binary/.meta/tests.toml (100%)
 rename exercises/{ => practice}/binary/Binary.cs (100%)
 rename exercises/{ => practice}/binary/Binary.csproj (100%)
 rename exercises/{ => practice}/binary/BinaryTests.cs (100%)
 rename exercises/{ => practice}/binary/Example.cs (100%)
 rename exercises/{ => practice}/binary/README.md (100%)
 rename exercises/{ => practice}/bob/.editorconfig (100%)
 rename exercises/{ => practice}/bob/.meta/tests.toml (100%)
 rename exercises/{ => practice}/bob/Bob.cs (100%)
 rename exercises/{ => practice}/bob/Bob.csproj (100%)
 rename exercises/{ => practice}/bob/BobTests.cs (100%)
 rename exercises/{ => practice}/bob/Example.cs (100%)
 rename exercises/{ => practice}/bob/README.md (100%)
 rename exercises/{ => practice}/book-store/.editorconfig (100%)
 rename exercises/{ => practice}/book-store/.meta/tests.toml (100%)
 rename exercises/{ => practice}/book-store/BookStore.cs (100%)
 rename exercises/{ => practice}/book-store/BookStore.csproj (100%)
 rename exercises/{ => practice}/book-store/BookStoreTests.cs (100%)
 rename exercises/{ => practice}/book-store/Example.cs (100%)
 rename exercises/{ => practice}/book-store/README.md (100%)
 rename exercises/{ => practice}/bowling/.editorconfig (100%)
 rename exercises/{ => practice}/bowling/.meta/tests.toml (100%)
 rename exercises/{ => practice}/bowling/Bowling.cs (100%)
 rename exercises/{ => practice}/bowling/Bowling.csproj (100%)
 rename exercises/{ => practice}/bowling/BowlingTests.cs (100%)
 rename exercises/{ => practice}/bowling/Example.cs (100%)
 rename exercises/{ => practice}/bowling/README.md (100%)
 rename exercises/{ => practice}/change/.editorconfig (100%)
 rename exercises/{ => practice}/change/.meta/tests.toml (100%)
 rename exercises/{ => practice}/change/Change.cs (100%)
 rename exercises/{ => practice}/change/Change.csproj (100%)
 rename exercises/{ => practice}/change/ChangeTests.cs (100%)
 rename exercises/{ => practice}/change/Example.cs (100%)
 rename exercises/{ => practice}/change/README.md (100%)
 rename exercises/{ => practice}/circular-buffer/.editorconfig (100%)
 rename exercises/{ => practice}/circular-buffer/.meta/tests.toml (100%)
 rename exercises/{ => practice}/circular-buffer/CircularBuffer.cs (100%)
 rename exercises/{ => practice}/circular-buffer/CircularBuffer.csproj (100%)
 rename exercises/{ => practice}/circular-buffer/CircularBufferTests.cs (100%)
 rename exercises/{ => practice}/circular-buffer/Example.cs (100%)
 rename exercises/{ => practice}/circular-buffer/README.md (100%)
 rename exercises/{ => practice}/clock/.editorconfig (100%)
 rename exercises/{ => practice}/clock/.meta/hints.md (100%)
 rename exercises/{ => practice}/clock/.meta/tests.toml (100%)
 rename exercises/{ => practice}/clock/Clock.cs (100%)
 rename exercises/{ => practice}/clock/Clock.csproj (100%)
 rename exercises/{ => practice}/clock/ClockTests.cs (100%)
 rename exercises/{ => practice}/clock/Example.cs (100%)
 rename exercises/{ => practice}/clock/README.md (100%)
 rename exercises/{ => practice}/collatz-conjecture/.editorconfig (100%)
 rename exercises/{ => practice}/collatz-conjecture/.meta/tests.toml (100%)
 rename exercises/{ => practice}/collatz-conjecture/CollatzConjecture.cs (100%)
 rename exercises/{ => practice}/collatz-conjecture/CollatzConjecture.csproj (100%)
 rename exercises/{ => practice}/collatz-conjecture/CollatzConjectureTests.cs (100%)
 rename exercises/{ => practice}/collatz-conjecture/Example.cs (100%)
 rename exercises/{ => practice}/collatz-conjecture/README.md (100%)
 rename exercises/{ => practice}/complex-numbers/.editorconfig (100%)
 rename exercises/{ => practice}/complex-numbers/.meta/tests.toml (100%)
 rename exercises/{ => practice}/complex-numbers/ComplexNumbers.cs (100%)
 rename exercises/{ => practice}/complex-numbers/ComplexNumbers.csproj (100%)
 rename exercises/{ => practice}/complex-numbers/ComplexNumbersTests.cs (100%)
 rename exercises/{ => practice}/complex-numbers/Example.cs (100%)
 rename exercises/{ => practice}/complex-numbers/README.md (100%)
 rename exercises/{ => practice}/connect/.editorconfig (100%)
 rename exercises/{ => practice}/connect/.meta/tests.toml (100%)
 rename exercises/{ => practice}/connect/Connect.cs (100%)
 rename exercises/{ => practice}/connect/Connect.csproj (100%)
 rename exercises/{ => practice}/connect/ConnectTests.cs (100%)
 rename exercises/{ => practice}/connect/Example.cs (100%)
 rename exercises/{ => practice}/connect/README.md (100%)
 rename exercises/{ => practice}/crypto-square/.editorconfig (100%)
 rename exercises/{ => practice}/crypto-square/.meta/tests.toml (100%)
 rename exercises/{ => practice}/crypto-square/CryptoSquare.cs (100%)
 rename exercises/{ => practice}/crypto-square/CryptoSquare.csproj (100%)
 rename exercises/{ => practice}/crypto-square/CryptoSquareTests.cs (100%)
 rename exercises/{ => practice}/crypto-square/Example.cs (100%)
 rename exercises/{ => practice}/crypto-square/README.md (100%)
 rename exercises/{ => practice}/custom-set/.editorconfig (100%)
 rename exercises/{ => practice}/custom-set/.meta/hints.md (100%)
 rename exercises/{ => practice}/custom-set/.meta/tests.toml (100%)
 rename exercises/{ => practice}/custom-set/CustomSet.cs (100%)
 rename exercises/{ => practice}/custom-set/CustomSet.csproj (100%)
 rename exercises/{ => practice}/custom-set/CustomSetTests.cs (100%)
 rename exercises/{ => practice}/custom-set/Example.cs (100%)
 rename exercises/{ => practice}/custom-set/README.md (100%)
 rename exercises/{ => practice}/darts/.editorconfig (100%)
 rename exercises/{ => practice}/darts/.meta/tests.toml (100%)
 rename exercises/{ => practice}/darts/Darts.cs (100%)
 rename exercises/{ => practice}/darts/Darts.csproj (100%)
 rename exercises/{ => practice}/darts/DartsTests.cs (100%)
 rename exercises/{ => practice}/darts/Example.cs (100%)
 rename exercises/{ => practice}/darts/README.md (100%)
 rename exercises/{ => practice}/diamond/.editorconfig (100%)
 rename exercises/{ => practice}/diamond/.meta/hints.md (100%)
 rename exercises/{ => practice}/diamond/.meta/tests.toml (100%)
 rename exercises/{ => practice}/diamond/Diamond.cs (100%)
 rename exercises/{ => practice}/diamond/Diamond.csproj (100%)
 rename exercises/{ => practice}/diamond/DiamondTests.cs (100%)
 rename exercises/{ => practice}/diamond/Example.cs (100%)
 rename exercises/{ => practice}/diamond/README.md (100%)
 rename exercises/{ => practice}/difference-of-squares/.editorconfig (100%)
 rename exercises/{ => practice}/difference-of-squares/.meta/hints.md (100%)
 rename exercises/{ => practice}/difference-of-squares/.meta/tests.toml (100%)
 rename exercises/{ => practice}/difference-of-squares/DifferenceOfSquares.cs (100%)
 rename exercises/{ => practice}/difference-of-squares/DifferenceOfSquares.csproj (100%)
 rename exercises/{ => practice}/difference-of-squares/DifferenceOfSquaresTests.cs (100%)
 rename exercises/{ => practice}/difference-of-squares/Example.cs (100%)
 rename exercises/{ => practice}/difference-of-squares/README.md (100%)
 rename exercises/{ => practice}/diffie-hellman/.editorconfig (100%)
 rename exercises/{ => practice}/diffie-hellman/.meta/hints.md (100%)
 rename exercises/{ => practice}/diffie-hellman/.meta/tests.toml (100%)
 rename exercises/{ => practice}/diffie-hellman/DiffieHellman.cs (100%)
 rename exercises/{ => practice}/diffie-hellman/DiffieHellman.csproj (100%)
 rename exercises/{ => practice}/diffie-hellman/DiffieHellmanTests.cs (100%)
 rename exercises/{ => practice}/diffie-hellman/Example.cs (100%)
 rename exercises/{ => practice}/diffie-hellman/README.md (100%)
 rename exercises/{ => practice}/dnd-character/.editorconfig (100%)
 rename exercises/{ => practice}/dnd-character/.meta/tests.toml (100%)
 rename exercises/{ => practice}/dnd-character/DndCharacter.cs (100%)
 rename exercises/{ => practice}/dnd-character/DndCharacter.csproj (100%)
 rename exercises/{ => practice}/dnd-character/DndCharacterTests.cs (100%)
 rename exercises/{ => practice}/dnd-character/Example.cs (100%)
 rename exercises/{ => practice}/dnd-character/README.md (100%)
 rename exercises/{ => practice}/dominoes/.editorconfig (100%)
 rename exercises/{ => practice}/dominoes/.meta/tests.toml (100%)
 rename exercises/{ => practice}/dominoes/Dominoes.cs (100%)
 rename exercises/{ => practice}/dominoes/Dominoes.csproj (100%)
 rename exercises/{ => practice}/dominoes/DominoesTests.cs (100%)
 rename exercises/{ => practice}/dominoes/Example.cs (100%)
 rename exercises/{ => practice}/dominoes/README.md (100%)
 rename exercises/{ => practice}/dot-dsl/.editorconfig (100%)
 rename exercises/{ => practice}/dot-dsl/.meta/hints.md (100%)
 rename exercises/{ => practice}/dot-dsl/DotDsl.cs (100%)
 rename exercises/{ => practice}/dot-dsl/DotDsl.csproj (100%)
 rename exercises/{ => practice}/dot-dsl/DotDslTests.cs (100%)
 rename exercises/{ => practice}/dot-dsl/Example.cs (100%)
 rename exercises/{ => practice}/dot-dsl/README.md (100%)
 rename exercises/{ => practice}/error-handling/.editorconfig (100%)
 rename exercises/{ => practice}/error-handling/ErrorHandling.cs (100%)
 rename exercises/{ => practice}/error-handling/ErrorHandling.csproj (100%)
 rename exercises/{ => practice}/error-handling/ErrorHandlingTests.cs (100%)
 rename exercises/{ => practice}/error-handling/Example.cs (100%)
 rename exercises/{ => practice}/error-handling/README.md (100%)
 rename exercises/{ => practice}/etl/.editorconfig (100%)
 rename exercises/{ => practice}/etl/.meta/tests.toml (100%)
 rename exercises/{ => practice}/etl/Etl.cs (100%)
 rename exercises/{ => practice}/etl/Etl.csproj (100%)
 rename exercises/{ => practice}/etl/EtlTests.cs (100%)
 rename exercises/{ => practice}/etl/Example.cs (100%)
 rename exercises/{ => practice}/etl/README.md (100%)
 rename exercises/{ => practice}/flatten-array/.editorconfig (100%)
 rename exercises/{ => practice}/flatten-array/.meta/tests.toml (100%)
 rename exercises/{ => practice}/flatten-array/Example.cs (100%)
 rename exercises/{ => practice}/flatten-array/FlattenArray.cs (100%)
 rename exercises/{ => practice}/flatten-array/FlattenArray.csproj (100%)
 rename exercises/{ => practice}/flatten-array/FlattenArrayTests.cs (100%)
 rename exercises/{ => practice}/flatten-array/README.md (100%)
 rename exercises/{ => practice}/food-chain/.editorconfig (100%)
 rename exercises/{ => practice}/food-chain/.meta/hints.md (100%)
 rename exercises/{ => practice}/food-chain/.meta/tests.toml (100%)
 rename exercises/{ => practice}/food-chain/Example.cs (100%)
 rename exercises/{ => practice}/food-chain/FoodChain.cs (100%)
 rename exercises/{ => practice}/food-chain/FoodChain.csproj (100%)
 rename exercises/{ => practice}/food-chain/FoodChainTests.cs (100%)
 rename exercises/{ => practice}/food-chain/README.md (100%)
 rename exercises/{ => practice}/forth/.editorconfig (100%)
 rename exercises/{ => practice}/forth/.meta/hints.md (100%)
 rename exercises/{ => practice}/forth/.meta/tests.toml (100%)
 rename exercises/{ => practice}/forth/Example.cs (100%)
 rename exercises/{ => practice}/forth/Forth.cs (100%)
 rename exercises/{ => practice}/forth/Forth.csproj (100%)
 rename exercises/{ => practice}/forth/ForthTests.cs (100%)
 rename exercises/{ => practice}/forth/README.md (100%)
 rename exercises/{ => practice}/gigasecond/.editorconfig (100%)
 rename exercises/{ => practice}/gigasecond/.meta/tests.toml (100%)
 rename exercises/{ => practice}/gigasecond/Example.cs (100%)
 rename exercises/{ => practice}/gigasecond/Gigasecond.cs (100%)
 rename exercises/{ => practice}/gigasecond/Gigasecond.csproj (100%)
 rename exercises/{ => practice}/gigasecond/GigasecondTests.cs (100%)
 rename exercises/{ => practice}/gigasecond/README.md (100%)
 rename exercises/{ => practice}/go-counting/.editorconfig (100%)
 rename exercises/{ => practice}/go-counting/.meta/tests.toml (100%)
 rename exercises/{ => practice}/go-counting/Example.cs (100%)
 rename exercises/{ => practice}/go-counting/GoCounting.cs (100%)
 rename exercises/{ => practice}/go-counting/GoCounting.csproj (100%)
 rename exercises/{ => practice}/go-counting/GoCountingTests.cs (100%)
 rename exercises/{ => practice}/go-counting/README.md (100%)
 rename exercises/{ => practice}/grade-school/.editorconfig (100%)
 rename exercises/{ => practice}/grade-school/.meta/tests.toml (100%)
 rename exercises/{ => practice}/grade-school/Example.cs (100%)
 rename exercises/{ => practice}/grade-school/GradeSchool.cs (100%)
 rename exercises/{ => practice}/grade-school/GradeSchool.csproj (100%)
 rename exercises/{ => practice}/grade-school/GradeSchoolTests.cs (100%)
 rename exercises/{ => practice}/grade-school/README.md (100%)
 rename exercises/{ => practice}/grains/.editorconfig (100%)
 rename exercises/{ => practice}/grains/.meta/tests.toml (100%)
 rename exercises/{ => practice}/grains/Example.cs (100%)
 rename exercises/{ => practice}/grains/Grains.cs (100%)
 rename exercises/{ => practice}/grains/Grains.csproj (100%)
 rename exercises/{ => practice}/grains/GrainsTests.cs (100%)
 rename exercises/{ => practice}/grains/README.md (100%)
 rename exercises/{ => practice}/grep/.editorconfig (100%)
 rename exercises/{ => practice}/grep/.meta/tests.toml (100%)
 rename exercises/{ => practice}/grep/Example.cs (100%)
 rename exercises/{ => practice}/grep/Grep.cs (100%)
 rename exercises/{ => practice}/grep/Grep.csproj (100%)
 rename exercises/{ => practice}/grep/GrepTests.cs (100%)
 rename exercises/{ => practice}/grep/README.md (100%)
 rename exercises/{ => practice}/hamming/.editorconfig (100%)
 rename exercises/{ => practice}/hamming/.meta/tests.toml (100%)
 rename exercises/{ => practice}/hamming/Example.cs (100%)
 rename exercises/{ => practice}/hamming/Hamming.cs (100%)
 rename exercises/{ => practice}/hamming/Hamming.csproj (100%)
 rename exercises/{ => practice}/hamming/HammingTests.cs (100%)
 rename exercises/{ => practice}/hamming/README.md (100%)
 rename exercises/{ => practice}/hangman/.editorconfig (100%)
 rename exercises/{ => practice}/hangman/.meta/hints.md (100%)
 rename exercises/{ => practice}/hangman/Example.cs (100%)
 rename exercises/{ => practice}/hangman/Hangman.cs (100%)
 rename exercises/{ => practice}/hangman/Hangman.csproj (100%)
 rename exercises/{ => practice}/hangman/HangmanTests.cs (100%)
 rename exercises/{ => practice}/hangman/README.md (100%)
 rename exercises/{ => practice}/hello-world/.editorconfig (100%)
 rename exercises/{ => practice}/hello-world/.meta/tests.toml (100%)
 rename exercises/{ => practice}/hello-world/Example.cs (100%)
 rename exercises/{ => practice}/hello-world/HelloWorld.cs (100%)
 rename exercises/{ => practice}/hello-world/HelloWorld.csproj (100%)
 rename exercises/{ => practice}/hello-world/HelloWorldTests.cs (100%)
 rename exercises/{ => practice}/hello-world/README.md (100%)
 rename exercises/{ => practice}/hexadecimal/.editorconfig (100%)
 rename exercises/{ => practice}/hexadecimal/Example.cs (100%)
 rename exercises/{ => practice}/hexadecimal/Hexadecimal.cs (100%)
 rename exercises/{ => practice}/hexadecimal/Hexadecimal.csproj (100%)
 rename exercises/{ => practice}/hexadecimal/HexadecimalTests.cs (100%)
 rename exercises/{ => practice}/hexadecimal/README.md (100%)
 rename exercises/{ => practice}/high-scores/.editorconfig (100%)
 rename exercises/{ => practice}/high-scores/.meta/tests.toml (100%)
 rename exercises/{ => practice}/high-scores/Example.cs (100%)
 rename exercises/{ => practice}/high-scores/HighScores.cs (100%)
 rename exercises/{ => practice}/high-scores/HighScores.csproj (100%)
 rename exercises/{ => practice}/high-scores/HighScoresTests.cs (100%)
 rename exercises/{ => practice}/high-scores/README.md (100%)
 rename exercises/{ => practice}/house/.editorconfig (100%)
 rename exercises/{ => practice}/house/.meta/hints.md (100%)
 rename exercises/{ => practice}/house/.meta/tests.toml (100%)
 rename exercises/{ => practice}/house/Example.cs (100%)
 rename exercises/{ => practice}/house/House.cs (100%)
 rename exercises/{ => practice}/house/House.csproj (100%)
 rename exercises/{ => practice}/house/HouseTests.cs (100%)
 rename exercises/{ => practice}/house/README.md (100%)
 rename exercises/{ => practice}/isbn-verifier/.editorconfig (100%)
 rename exercises/{ => practice}/isbn-verifier/.meta/tests.toml (100%)
 rename exercises/{ => practice}/isbn-verifier/Example.cs (100%)
 rename exercises/{ => practice}/isbn-verifier/IsbnVerifier.cs (100%)
 rename exercises/{ => practice}/isbn-verifier/IsbnVerifier.csproj (100%)
 rename exercises/{ => practice}/isbn-verifier/IsbnVerifierTests.cs (100%)
 rename exercises/{ => practice}/isbn-verifier/README.md (100%)
 rename exercises/{ => practice}/isogram/.editorconfig (100%)
 rename exercises/{ => practice}/isogram/.meta/tests.toml (100%)
 rename exercises/{ => practice}/isogram/Example.cs (100%)
 rename exercises/{ => practice}/isogram/Isogram.cs (100%)
 rename exercises/{ => practice}/isogram/Isogram.csproj (100%)
 rename exercises/{ => practice}/isogram/IsogramTests.cs (100%)
 rename exercises/{ => practice}/isogram/README.md (100%)
 rename exercises/{ => practice}/kindergarten-garden/.editorconfig (100%)
 rename exercises/{ => practice}/kindergarten-garden/.meta/tests.toml (100%)
 rename exercises/{ => practice}/kindergarten-garden/Example.cs (100%)
 rename exercises/{ => practice}/kindergarten-garden/KindergartenGarden.cs (100%)
 rename exercises/{ => practice}/kindergarten-garden/KindergartenGarden.csproj (100%)
 rename exercises/{ => practice}/kindergarten-garden/KindergartenGardenTests.cs (100%)
 rename exercises/{ => practice}/kindergarten-garden/README.md (100%)
 rename exercises/{ => practice}/largest-series-product/.editorconfig (100%)
 rename exercises/{ => practice}/largest-series-product/.meta/tests.toml (100%)
 rename exercises/{ => practice}/largest-series-product/Example.cs (97%)
 rename exercises/{ => practice}/largest-series-product/LargestSeriesProduct.cs (100%)
 rename exercises/{ => practice}/largest-series-product/LargestSeriesProduct.csproj (100%)
 rename exercises/{ => practice}/largest-series-product/LargestSeriesProductTests.cs (100%)
 rename exercises/{ => practice}/largest-series-product/README.md (100%)
 rename exercises/{ => practice}/leap/.editorconfig (100%)
 rename exercises/{ => practice}/leap/.meta/hints.md (100%)
 rename exercises/{ => practice}/leap/.meta/tests.toml (100%)
 rename exercises/{ => practice}/leap/Example.cs (100%)
 rename exercises/{ => practice}/leap/Leap.cs (100%)
 rename exercises/{ => practice}/leap/Leap.csproj (100%)
 rename exercises/{ => practice}/leap/LeapTests.cs (100%)
 rename exercises/{ => practice}/leap/README.md (100%)
 rename exercises/{ => practice}/ledger/.editorconfig (100%)
 rename exercises/{ => practice}/ledger/Example.cs (100%)
 rename exercises/{ => practice}/ledger/Ledger.cs (100%)
 rename exercises/{ => practice}/ledger/Ledger.csproj (100%)
 rename exercises/{ => practice}/ledger/LedgerTests.cs (100%)
 rename exercises/{ => practice}/ledger/README.md (100%)
 rename exercises/{ => practice}/linked-list/.editorconfig (100%)
 rename exercises/{ => practice}/linked-list/Example.cs (100%)
 rename exercises/{ => practice}/linked-list/LinkedList.cs (100%)
 rename exercises/{ => practice}/linked-list/LinkedList.csproj (100%)
 rename exercises/{ => practice}/linked-list/LinkedListTests.cs (100%)
 rename exercises/{ => practice}/linked-list/README.md (100%)
 rename exercises/{ => practice}/list-ops/.editorconfig (100%)
 rename exercises/{ => practice}/list-ops/.meta/hints.md (100%)
 rename exercises/{ => practice}/list-ops/.meta/tests.toml (100%)
 rename exercises/{ => practice}/list-ops/Example.cs (100%)
 rename exercises/{ => practice}/list-ops/ListOps.cs (100%)
 rename exercises/{ => practice}/list-ops/ListOps.csproj (100%)
 rename exercises/{ => practice}/list-ops/ListOpsTests.cs (100%)
 rename exercises/{ => practice}/list-ops/README.md (100%)
 rename exercises/{ => practice}/luhn/.editorconfig (100%)
 rename exercises/{ => practice}/luhn/.meta/tests.toml (100%)
 rename exercises/{ => practice}/luhn/Example.cs (100%)
 rename exercises/{ => practice}/luhn/Luhn.cs (100%)
 rename exercises/{ => practice}/luhn/Luhn.csproj (100%)
 rename exercises/{ => practice}/luhn/LuhnTests.cs (100%)
 rename exercises/{ => practice}/luhn/README.md (100%)
 rename exercises/{ => practice}/markdown/.editorconfig (100%)
 rename exercises/{ => practice}/markdown/.meta/hints.md (100%)
 rename exercises/{ => practice}/markdown/.meta/tests.toml (100%)
 rename exercises/{ => practice}/markdown/Example.cs (100%)
 rename exercises/{ => practice}/markdown/Markdown.cs (100%)
 rename exercises/{ => practice}/markdown/Markdown.csproj (100%)
 rename exercises/{ => practice}/markdown/MarkdownTests.cs (100%)
 rename exercises/{ => practice}/markdown/README.md (100%)
 rename exercises/{ => practice}/matching-brackets/.editorconfig (100%)
 rename exercises/{ => practice}/matching-brackets/.meta/tests.toml (100%)
 rename exercises/{ => practice}/matching-brackets/Example.cs (100%)
 rename exercises/{ => practice}/matching-brackets/MatchingBrackets.cs (100%)
 rename exercises/{ => practice}/matching-brackets/MatchingBrackets.csproj (100%)
 rename exercises/{ => practice}/matching-brackets/MatchingBracketsTests.cs (100%)
 rename exercises/{ => practice}/matching-brackets/README.md (100%)
 rename exercises/{ => practice}/matrix/.editorconfig (100%)
 rename exercises/{ => practice}/matrix/.meta/tests.toml (100%)
 rename exercises/{ => practice}/matrix/Example.cs (100%)
 rename exercises/{ => practice}/matrix/Matrix.cs (100%)
 rename exercises/{ => practice}/matrix/Matrix.csproj (100%)
 rename exercises/{ => practice}/matrix/MatrixTests.cs (100%)
 rename exercises/{ => practice}/matrix/README.md (100%)
 rename exercises/{ => practice}/meetup/.editorconfig (100%)
 rename exercises/{ => practice}/meetup/.meta/tests.toml (100%)
 rename exercises/{ => practice}/meetup/Example.cs (100%)
 rename exercises/{ => practice}/meetup/Meetup.cs (100%)
 rename exercises/{ => practice}/meetup/Meetup.csproj (100%)
 rename exercises/{ => practice}/meetup/MeetupTests.cs (100%)
 rename exercises/{ => practice}/meetup/README.md (100%)
 rename exercises/{ => practice}/minesweeper/.editorconfig (100%)
 rename exercises/{ => practice}/minesweeper/.meta/tests.toml (100%)
 rename exercises/{ => practice}/minesweeper/Example.cs (100%)
 rename exercises/{ => practice}/minesweeper/Minesweeper.cs (100%)
 rename exercises/{ => practice}/minesweeper/Minesweeper.csproj (100%)
 rename exercises/{ => practice}/minesweeper/MinesweeperTests.cs (100%)
 rename exercises/{ => practice}/minesweeper/README.md (100%)
 rename exercises/{ => practice}/nth-prime/.editorconfig (100%)
 rename exercises/{ => practice}/nth-prime/.meta/hints.md (100%)
 rename exercises/{ => practice}/nth-prime/.meta/tests.toml (100%)
 rename exercises/{ => practice}/nth-prime/Example.cs (100%)
 rename exercises/{ => practice}/nth-prime/NthPrime.cs (100%)
 rename exercises/{ => practice}/nth-prime/NthPrime.csproj (100%)
 rename exercises/{ => practice}/nth-prime/NthPrimeTests.cs (100%)
 rename exercises/{ => practice}/nth-prime/README.md (100%)
 rename exercises/{ => practice}/nucleotide-count/.editorconfig (100%)
 rename exercises/{ => practice}/nucleotide-count/.meta/hints.md (100%)
 rename exercises/{ => practice}/nucleotide-count/.meta/tests.toml (100%)
 rename exercises/{ => practice}/nucleotide-count/Example.cs (100%)
 rename exercises/{ => practice}/nucleotide-count/NucleotideCount.cs (100%)
 rename exercises/{ => practice}/nucleotide-count/NucleotideCount.csproj (100%)
 rename exercises/{ => practice}/nucleotide-count/NucleotideCountTests.cs (100%)
 rename exercises/{ => practice}/nucleotide-count/README.md (100%)
 rename exercises/{ => practice}/ocr-numbers/.editorconfig (100%)
 rename exercises/{ => practice}/ocr-numbers/.meta/tests.toml (100%)
 rename exercises/{ => practice}/ocr-numbers/Example.cs (100%)
 rename exercises/{ => practice}/ocr-numbers/OcrNumbers.cs (100%)
 rename exercises/{ => practice}/ocr-numbers/OcrNumbers.csproj (100%)
 rename exercises/{ => practice}/ocr-numbers/OcrNumbersTests.cs (100%)
 rename exercises/{ => practice}/ocr-numbers/README.md (100%)
 rename exercises/{ => practice}/octal/.editorconfig (100%)
 rename exercises/{ => practice}/octal/Example.cs (100%)
 rename exercises/{ => practice}/octal/Octal.cs (100%)
 rename exercises/{ => practice}/octal/Octal.csproj (100%)
 rename exercises/{ => practice}/octal/OctalTests.cs (100%)
 rename exercises/{ => practice}/octal/README.md (100%)
 rename exercises/{ => practice}/palindrome-products/.editorconfig (100%)
 rename exercises/{ => practice}/palindrome-products/.meta/hints.md (100%)
 rename exercises/{ => practice}/palindrome-products/.meta/tests.toml (100%)
 rename exercises/{ => practice}/palindrome-products/Example.cs (100%)
 rename exercises/{ => practice}/palindrome-products/PalindromeProducts.cs (100%)
 rename exercises/{ => practice}/palindrome-products/PalindromeProducts.csproj (100%)
 rename exercises/{ => practice}/palindrome-products/PalindromeProductsTests.cs (100%)
 rename exercises/{ => practice}/palindrome-products/README.md (100%)
 rename exercises/{ => practice}/pangram/.editorconfig (100%)
 rename exercises/{ => practice}/pangram/.meta/tests.toml (100%)
 rename exercises/{ => practice}/pangram/Example.cs (100%)
 rename exercises/{ => practice}/pangram/Pangram.cs (100%)
 rename exercises/{ => practice}/pangram/Pangram.csproj (100%)
 rename exercises/{ => practice}/pangram/PangramTests.cs (100%)
 rename exercises/{ => practice}/pangram/README.md (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/.editorconfig (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/Example.cs (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/ParallelLetterFrequency.cs (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/ParallelLetterFrequency.csproj (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/ParallelLetterFrequencyTests.cs (100%)
 rename exercises/{ => practice}/parallel-letter-frequency/README.md (100%)
 rename exercises/{ => practice}/pascals-triangle/.editorconfig (100%)
 rename exercises/{ => practice}/pascals-triangle/.meta/tests.toml (100%)
 rename exercises/{ => practice}/pascals-triangle/Example.cs (100%)
 rename exercises/{ => practice}/pascals-triangle/PascalsTriangle.cs (100%)
 rename exercises/{ => practice}/pascals-triangle/PascalsTriangle.csproj (100%)
 rename exercises/{ => practice}/pascals-triangle/PascalsTriangleTests.cs (100%)
 rename exercises/{ => practice}/pascals-triangle/README.md (100%)
 rename exercises/{ => practice}/perfect-numbers/.editorconfig (100%)
 rename exercises/{ => practice}/perfect-numbers/.meta/tests.toml (100%)
 rename exercises/{ => practice}/perfect-numbers/Example.cs (100%)
 rename exercises/{ => practice}/perfect-numbers/PerfectNumbers.cs (100%)
 rename exercises/{ => practice}/perfect-numbers/PerfectNumbers.csproj (100%)
 rename exercises/{ => practice}/perfect-numbers/PerfectNumbersTests.cs (100%)
 rename exercises/{ => practice}/perfect-numbers/README.md (100%)
 rename exercises/{ => practice}/phone-number/.editorconfig (100%)
 rename exercises/{ => practice}/phone-number/.meta/tests.toml (100%)
 rename exercises/{ => practice}/phone-number/Example.cs (100%)
 rename exercises/{ => practice}/phone-number/PhoneNumber.cs (100%)
 rename exercises/{ => practice}/phone-number/PhoneNumber.csproj (100%)
 rename exercises/{ => practice}/phone-number/PhoneNumberTests.cs (100%)
 rename exercises/{ => practice}/phone-number/README.md (100%)
 rename exercises/{ => practice}/pig-latin/.editorconfig (100%)
 rename exercises/{ => practice}/pig-latin/.meta/tests.toml (100%)
 rename exercises/{ => practice}/pig-latin/Example.cs (100%)
 rename exercises/{ => practice}/pig-latin/PigLatin.cs (100%)
 rename exercises/{ => practice}/pig-latin/PigLatin.csproj (100%)
 rename exercises/{ => practice}/pig-latin/PigLatinTests.cs (100%)
 rename exercises/{ => practice}/pig-latin/README.md (100%)
 rename exercises/{ => practice}/poker/.editorconfig (100%)
 rename exercises/{ => practice}/poker/.meta/tests.toml (100%)
 rename exercises/{ => practice}/poker/Example.cs (100%)
 rename exercises/{ => practice}/poker/Poker.cs (100%)
 rename exercises/{ => practice}/poker/Poker.csproj (100%)
 rename exercises/{ => practice}/poker/PokerTests.cs (100%)
 rename exercises/{ => practice}/poker/README.md (100%)
 rename exercises/{ => practice}/pov/.editorconfig (100%)
 rename exercises/{ => practice}/pov/.meta/tests.toml (100%)
 rename exercises/{ => practice}/pov/Example.cs (100%)
 rename exercises/{ => practice}/pov/Pov.cs (100%)
 rename exercises/{ => practice}/pov/Pov.csproj (100%)
 rename exercises/{ => practice}/pov/PovTests.cs (100%)
 rename exercises/{ => practice}/pov/README.md (100%)
 rename exercises/{ => practice}/prime-factors/.editorconfig (100%)
 rename exercises/{ => practice}/prime-factors/.meta/tests.toml (100%)
 rename exercises/{ => practice}/prime-factors/Example.cs (100%)
 rename exercises/{ => practice}/prime-factors/PrimeFactors.cs (100%)
 rename exercises/{ => practice}/prime-factors/PrimeFactors.csproj (100%)
 rename exercises/{ => practice}/prime-factors/PrimeFactorsTests.cs (100%)
 rename exercises/{ => practice}/prime-factors/README.md (100%)
 rename exercises/{ => practice}/protein-translation/.editorconfig (100%)
 rename exercises/{ => practice}/protein-translation/.meta/tests.toml (100%)
 rename exercises/{ => practice}/protein-translation/Example.cs (100%)
 rename exercises/{ => practice}/protein-translation/ProteinTranslation.cs (100%)
 rename exercises/{ => practice}/protein-translation/ProteinTranslation.csproj (100%)
 rename exercises/{ => practice}/protein-translation/ProteinTranslationTests.cs (100%)
 rename exercises/{ => practice}/protein-translation/README.md (100%)
 rename exercises/{ => practice}/proverb/.editorconfig (100%)
 rename exercises/{ => practice}/proverb/.meta/hints.md (100%)
 rename exercises/{ => practice}/proverb/.meta/tests.toml (100%)
 rename exercises/{ => practice}/proverb/Example.cs (100%)
 rename exercises/{ => practice}/proverb/Proverb.cs (100%)
 rename exercises/{ => practice}/proverb/Proverb.csproj (100%)
 rename exercises/{ => practice}/proverb/ProverbTests.cs (100%)
 rename exercises/{ => practice}/proverb/README.md (100%)
 rename exercises/{ => practice}/pythagorean-triplet/.editorconfig (100%)
 rename exercises/{ => practice}/pythagorean-triplet/.meta/tests.toml (100%)
 rename exercises/{ => practice}/pythagorean-triplet/Example.cs (100%)
 rename exercises/{ => practice}/pythagorean-triplet/PythagoreanTriplet.cs (100%)
 rename exercises/{ => practice}/pythagorean-triplet/PythagoreanTriplet.csproj (100%)
 rename exercises/{ => practice}/pythagorean-triplet/PythagoreanTripletTests.cs (100%)
 rename exercises/{ => practice}/pythagorean-triplet/README.md (100%)
 rename exercises/{ => practice}/queen-attack/.editorconfig (100%)
 rename exercises/{ => practice}/queen-attack/.meta/tests.toml (100%)
 rename exercises/{ => practice}/queen-attack/Example.cs (100%)
 rename exercises/{ => practice}/queen-attack/QueenAttack.cs (100%)
 rename exercises/{ => practice}/queen-attack/QueenAttack.csproj (100%)
 rename exercises/{ => practice}/queen-attack/QueenAttackTests.cs (100%)
 rename exercises/{ => practice}/queen-attack/README.md (100%)
 rename exercises/{ => practice}/rail-fence-cipher/.editorconfig (100%)
 rename exercises/{ => practice}/rail-fence-cipher/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rail-fence-cipher/Example.cs (100%)
 rename exercises/{ => practice}/rail-fence-cipher/README.md (100%)
 rename exercises/{ => practice}/rail-fence-cipher/RailFenceCipher.cs (100%)
 rename exercises/{ => practice}/rail-fence-cipher/RailFenceCipher.csproj (100%)
 rename exercises/{ => practice}/rail-fence-cipher/RailFenceCipherTests.cs (100%)
 rename exercises/{ => practice}/raindrops/.editorconfig (100%)
 rename exercises/{ => practice}/raindrops/.meta/tests.toml (100%)
 rename exercises/{ => practice}/raindrops/Example.cs (100%)
 rename exercises/{ => practice}/raindrops/README.md (100%)
 rename exercises/{ => practice}/raindrops/Raindrops.cs (100%)
 rename exercises/{ => practice}/raindrops/Raindrops.csproj (100%)
 rename exercises/{ => practice}/raindrops/RaindropsTests.cs (100%)
 rename exercises/{ => practice}/rational-numbers/.editorconfig (100%)
 rename exercises/{ => practice}/rational-numbers/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rational-numbers/Example.cs (100%)
 rename exercises/{ => practice}/rational-numbers/README.md (100%)
 rename exercises/{ => practice}/rational-numbers/RationalNumbers.cs (100%)
 rename exercises/{ => practice}/rational-numbers/RationalNumbers.csproj (100%)
 rename exercises/{ => practice}/rational-numbers/RationalNumbersTests.cs (100%)
 rename exercises/{ => practice}/rational-numbers/hints.md (100%)
 rename exercises/{ => practice}/react/.editorconfig (100%)
 rename exercises/{ => practice}/react/.meta/hints.md (100%)
 rename exercises/{ => practice}/react/.meta/tests.toml (100%)
 rename exercises/{ => practice}/react/Example.cs (100%)
 rename exercises/{ => practice}/react/README.md (100%)
 rename exercises/{ => practice}/react/React.cs (100%)
 rename exercises/{ => practice}/react/React.csproj (100%)
 rename exercises/{ => practice}/react/ReactTests.cs (100%)
 rename exercises/{ => practice}/rectangles/.editorconfig (100%)
 rename exercises/{ => practice}/rectangles/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rectangles/Example.cs (100%)
 rename exercises/{ => practice}/rectangles/README.md (100%)
 rename exercises/{ => practice}/rectangles/Rectangles.cs (100%)
 rename exercises/{ => practice}/rectangles/Rectangles.csproj (100%)
 rename exercises/{ => practice}/rectangles/RectanglesTests.cs (100%)
 rename exercises/{ => practice}/resistor-color-duo/.editorconfig (100%)
 rename exercises/{ => practice}/resistor-color-duo/.meta/tests.toml (100%)
 rename exercises/{ => practice}/resistor-color-duo/Example.cs (100%)
 rename exercises/{ => practice}/resistor-color-duo/README.md (100%)
 rename exercises/{ => practice}/resistor-color-duo/ResistorColorDuo.cs (100%)
 rename exercises/{ => practice}/resistor-color-duo/ResistorColorDuo.csproj (100%)
 rename exercises/{ => practice}/resistor-color-duo/ResistorColorDuoTests.cs (100%)
 rename exercises/{ => practice}/resistor-color-trio/.editorconfig (100%)
 rename exercises/{ => practice}/resistor-color-trio/.meta/tests.toml (100%)
 rename exercises/{ => practice}/resistor-color-trio/Example.cs (100%)
 rename exercises/{ => practice}/resistor-color-trio/README.md (100%)
 rename exercises/{ => practice}/resistor-color-trio/ResistorColorTrio.cs (100%)
 rename exercises/{ => practice}/resistor-color-trio/ResistorColorTrio.csproj (100%)
 rename exercises/{ => practice}/resistor-color-trio/ResistorColorTrioTests.cs (100%)
 rename exercises/{ => practice}/resistor-color/.editorconfig (100%)
 rename exercises/{ => practice}/resistor-color/.meta/tests.toml (100%)
 rename exercises/{ => practice}/resistor-color/Example.cs (100%)
 rename exercises/{ => practice}/resistor-color/README.md (100%)
 rename exercises/{ => practice}/resistor-color/ResistorColor.cs (100%)
 rename exercises/{ => practice}/resistor-color/ResistorColor.csproj (100%)
 rename exercises/{ => practice}/resistor-color/ResistorColorTests.cs (100%)
 rename exercises/{ => practice}/rest-api/.editorconfig (100%)
 rename exercises/{ => practice}/rest-api/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rest-api/Example.cs (100%)
 rename exercises/{ => practice}/rest-api/README.md (100%)
 rename exercises/{ => practice}/rest-api/RestApi.cs (100%)
 rename exercises/{ => practice}/rest-api/RestApi.csproj (100%)
 rename exercises/{ => practice}/rest-api/RestApiTests.cs (100%)
 rename exercises/{ => practice}/reverse-string/.editorconfig (100%)
 rename exercises/{ => practice}/reverse-string/.meta/tests.toml (100%)
 rename exercises/{ => practice}/reverse-string/Example.cs (100%)
 rename exercises/{ => practice}/reverse-string/README.md (100%)
 rename exercises/{ => practice}/reverse-string/ReverseString.cs (100%)
 rename exercises/{ => practice}/reverse-string/ReverseString.csproj (100%)
 rename exercises/{ => practice}/reverse-string/ReverseStringTests.cs (100%)
 rename exercises/{ => practice}/rna-transcription/.editorconfig (100%)
 rename exercises/{ => practice}/rna-transcription/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rna-transcription/Example.cs (100%)
 rename exercises/{ => practice}/rna-transcription/README.md (100%)
 rename exercises/{ => practice}/rna-transcription/RnaTranscription.cs (100%)
 rename exercises/{ => practice}/rna-transcription/RnaTranscription.csproj (100%)
 rename exercises/{ => practice}/rna-transcription/RnaTranscriptionTests.cs (100%)
 rename exercises/{ => practice}/robot-name/.editorconfig (100%)
 rename exercises/{ => practice}/robot-name/Example.cs (100%)
 rename exercises/{ => practice}/robot-name/README.md (100%)
 rename exercises/{ => practice}/robot-name/RobotName.cs (100%)
 rename exercises/{ => practice}/robot-name/RobotName.csproj (100%)
 rename exercises/{ => practice}/robot-name/RobotNameTests.cs (100%)
 rename exercises/{ => practice}/robot-simulator/.editorconfig (100%)
 rename exercises/{ => practice}/robot-simulator/.meta/tests.toml (100%)
 rename exercises/{ => practice}/robot-simulator/Example.cs (100%)
 rename exercises/{ => practice}/robot-simulator/README.md (100%)
 rename exercises/{ => practice}/robot-simulator/RobotSimulator.cs (100%)
 rename exercises/{ => practice}/robot-simulator/RobotSimulator.csproj (100%)
 rename exercises/{ => practice}/robot-simulator/RobotSimulatorTests.cs (100%)
 rename exercises/{ => practice}/roman-numerals/.editorconfig (100%)
 rename exercises/{ => practice}/roman-numerals/.meta/hints.md (100%)
 rename exercises/{ => practice}/roman-numerals/.meta/tests.toml (100%)
 rename exercises/{ => practice}/roman-numerals/Example.cs (100%)
 rename exercises/{ => practice}/roman-numerals/README.md (100%)
 rename exercises/{ => practice}/roman-numerals/RomanNumerals.cs (100%)
 rename exercises/{ => practice}/roman-numerals/RomanNumerals.csproj (100%)
 rename exercises/{ => practice}/roman-numerals/RomanNumeralsTests.cs (100%)
 rename exercises/{ => practice}/rotational-cipher/.editorconfig (100%)
 rename exercises/{ => practice}/rotational-cipher/.meta/tests.toml (100%)
 rename exercises/{ => practice}/rotational-cipher/Example.cs (100%)
 rename exercises/{ => practice}/rotational-cipher/README.md (100%)
 rename exercises/{ => practice}/rotational-cipher/RotationalCipher.cs (100%)
 rename exercises/{ => practice}/rotational-cipher/RotationalCipher.csproj (100%)
 rename exercises/{ => practice}/rotational-cipher/RotationalCipherTests.cs (100%)
 rename exercises/{ => practice}/run-length-encoding/.editorconfig (100%)
 rename exercises/{ => practice}/run-length-encoding/.meta/tests.toml (100%)
 rename exercises/{ => practice}/run-length-encoding/Example.cs (100%)
 rename exercises/{ => practice}/run-length-encoding/README.md (100%)
 rename exercises/{ => practice}/run-length-encoding/RunLengthEncoding.cs (100%)
 rename exercises/{ => practice}/run-length-encoding/RunLengthEncoding.csproj (100%)
 rename exercises/{ => practice}/run-length-encoding/RunLengthEncodingTests.cs (100%)
 rename exercises/{ => practice}/saddle-points/.editorconfig (100%)
 rename exercises/{ => practice}/saddle-points/.meta/hints.md (100%)
 rename exercises/{ => practice}/saddle-points/.meta/tests.toml (100%)
 rename exercises/{ => practice}/saddle-points/Example.cs (100%)
 rename exercises/{ => practice}/saddle-points/README.md (100%)
 rename exercises/{ => practice}/saddle-points/SaddlePoints.cs (100%)
 rename exercises/{ => practice}/saddle-points/SaddlePoints.csproj (100%)
 rename exercises/{ => practice}/saddle-points/SaddlePointsTests.cs (100%)
 rename exercises/{ => practice}/say/.editorconfig (100%)
 rename exercises/{ => practice}/say/.meta/tests.toml (100%)
 rename exercises/{ => practice}/say/Example.cs (100%)
 rename exercises/{ => practice}/say/README.md (100%)
 rename exercises/{ => practice}/say/Say.cs (100%)
 rename exercises/{ => practice}/say/Say.csproj (100%)
 rename exercises/{ => practice}/say/SayTests.cs (100%)
 rename exercises/{ => practice}/scale-generator/.editorconfig (100%)
 rename exercises/{ => practice}/scale-generator/.meta/tests.toml (100%)
 rename exercises/{ => practice}/scale-generator/Example.cs (100%)
 rename exercises/{ => practice}/scale-generator/README.md (100%)
 rename exercises/{ => practice}/scale-generator/ScaleGenerator.cs (100%)
 rename exercises/{ => practice}/scale-generator/ScaleGenerator.csproj (100%)
 rename exercises/{ => practice}/scale-generator/ScaleGeneratorTests.cs (100%)
 rename exercises/{ => practice}/scrabble-score/.editorconfig (100%)
 rename exercises/{ => practice}/scrabble-score/.meta/tests.toml (100%)
 rename exercises/{ => practice}/scrabble-score/Example.cs (100%)
 rename exercises/{ => practice}/scrabble-score/README.md (100%)
 rename exercises/{ => practice}/scrabble-score/ScrabbleScore.cs (100%)
 rename exercises/{ => practice}/scrabble-score/ScrabbleScore.csproj (100%)
 rename exercises/{ => practice}/scrabble-score/ScrabbleScoreTests.cs (100%)
 rename exercises/{ => practice}/secret-handshake/.editorconfig (100%)
 rename exercises/{ => practice}/secret-handshake/.meta/tests.toml (100%)
 rename exercises/{ => practice}/secret-handshake/Example.cs (100%)
 rename exercises/{ => practice}/secret-handshake/README.md (100%)
 rename exercises/{ => practice}/secret-handshake/SecretHandshake.cs (100%)
 rename exercises/{ => practice}/secret-handshake/SecretHandshake.csproj (100%)
 rename exercises/{ => practice}/secret-handshake/SecretHandshakeTests.cs (100%)
 rename exercises/{ => practice}/series/.editorconfig (100%)
 rename exercises/{ => practice}/series/.meta/tests.toml (100%)
 rename exercises/{ => practice}/series/Example.cs (100%)
 rename exercises/{ => practice}/series/README.md (100%)
 rename exercises/{ => practice}/series/Series.cs (100%)
 rename exercises/{ => practice}/series/Series.csproj (100%)
 rename exercises/{ => practice}/series/SeriesTests.cs (100%)
 rename exercises/{ => practice}/sgf-parsing/.editorconfig (100%)
 rename exercises/{ => practice}/sgf-parsing/.meta/hints.md (100%)
 rename exercises/{ => practice}/sgf-parsing/.meta/tests.toml (100%)
 rename exercises/{ => practice}/sgf-parsing/Example.cs (100%)
 rename exercises/{ => practice}/sgf-parsing/README.md (100%)
 rename exercises/{ => practice}/sgf-parsing/SgfParsing.cs (100%)
 rename exercises/{ => practice}/sgf-parsing/SgfParsing.csproj (100%)
 rename exercises/{ => practice}/sgf-parsing/SgfParsingTests.cs (100%)
 rename exercises/{ => practice}/sieve/.editorconfig (100%)
 rename exercises/{ => practice}/sieve/.meta/tests.toml (100%)
 rename exercises/{ => practice}/sieve/Example.cs (100%)
 rename exercises/{ => practice}/sieve/README.md (100%)
 rename exercises/{ => practice}/sieve/Sieve.cs (100%)
 rename exercises/{ => practice}/sieve/Sieve.csproj (100%)
 rename exercises/{ => practice}/sieve/SieveTests.cs (100%)
 rename exercises/{ => practice}/simple-cipher/.editorconfig (100%)
 rename exercises/{ => practice}/simple-cipher/.meta/tests.toml (100%)
 rename exercises/{ => practice}/simple-cipher/Example.cs (100%)
 rename exercises/{ => practice}/simple-cipher/README.md (100%)
 rename exercises/{ => practice}/simple-cipher/SimpleCipher.cs (100%)
 rename exercises/{ => practice}/simple-cipher/SimpleCipher.csproj (100%)
 rename exercises/{ => practice}/simple-cipher/SimpleCipherTests.cs (100%)
 rename exercises/{ => practice}/simple-linked-list/.editorconfig (100%)
 rename exercises/{ => practice}/simple-linked-list/.meta/hints.md (100%)
 rename exercises/{ => practice}/simple-linked-list/Example.cs (100%)
 rename exercises/{ => practice}/simple-linked-list/README.md (100%)
 rename exercises/{ => practice}/simple-linked-list/SimpleLinkedList.cs (100%)
 rename exercises/{ => practice}/simple-linked-list/SimpleLinkedList.csproj (100%)
 rename exercises/{ => practice}/simple-linked-list/SimpleLinkedListTests.cs (100%)
 rename exercises/{ => practice}/space-age/.editorconfig (100%)
 rename exercises/{ => practice}/space-age/.meta/tests.toml (100%)
 rename exercises/{ => practice}/space-age/Example.cs (100%)
 rename exercises/{ => practice}/space-age/README.md (100%)
 rename exercises/{ => practice}/space-age/SpaceAge.cs (100%)
 rename exercises/{ => practice}/space-age/SpaceAge.csproj (100%)
 rename exercises/{ => practice}/space-age/SpaceAgeTests.cs (100%)
 rename exercises/{ => practice}/spiral-matrix/.editorconfig (100%)
 rename exercises/{ => practice}/spiral-matrix/.meta/tests.toml (100%)
 rename exercises/{ => practice}/spiral-matrix/Example.cs (100%)
 rename exercises/{ => practice}/spiral-matrix/README.md (100%)
 rename exercises/{ => practice}/spiral-matrix/SpiralMatrix.cs (100%)
 rename exercises/{ => practice}/spiral-matrix/SpiralMatrix.csproj (100%)
 rename exercises/{ => practice}/spiral-matrix/SpiralMatrixTests.cs (100%)
 rename exercises/{ => practice}/strain/.editorconfig (100%)
 rename exercises/{ => practice}/strain/Example.cs (100%)
 rename exercises/{ => practice}/strain/README.md (100%)
 rename exercises/{ => practice}/strain/Strain.cs (100%)
 rename exercises/{ => practice}/strain/Strain.csproj (100%)
 rename exercises/{ => practice}/strain/StrainTests.cs (100%)
 rename exercises/{ => practice}/sublist/.editorconfig (100%)
 rename exercises/{ => practice}/sublist/.meta/hints.md (100%)
 rename exercises/{ => practice}/sublist/.meta/tests.toml (100%)
 rename exercises/{ => practice}/sublist/Example.cs (100%)
 rename exercises/{ => practice}/sublist/README.md (100%)
 rename exercises/{ => practice}/sublist/Sublist.cs (100%)
 rename exercises/{ => practice}/sublist/Sublist.csproj (100%)
 rename exercises/{ => practice}/sublist/SublistTests.cs (100%)
 rename exercises/{ => practice}/sum-of-multiples/.editorconfig (100%)
 rename exercises/{ => practice}/sum-of-multiples/.meta/hints.md (100%)
 rename exercises/{ => practice}/sum-of-multiples/.meta/tests.toml (100%)
 rename exercises/{ => practice}/sum-of-multiples/Example.cs (100%)
 rename exercises/{ => practice}/sum-of-multiples/README.md (100%)
 rename exercises/{ => practice}/sum-of-multiples/SumOfMultiples.cs (100%)
 rename exercises/{ => practice}/sum-of-multiples/SumOfMultiples.csproj (100%)
 rename exercises/{ => practice}/sum-of-multiples/SumOfMultiplesTests.cs (100%)
 rename exercises/{ => practice}/tournament/.editorconfig (100%)
 rename exercises/{ => practice}/tournament/.meta/tests.toml (100%)
 rename exercises/{ => practice}/tournament/Example.cs (100%)
 rename exercises/{ => practice}/tournament/README.md (100%)
 rename exercises/{ => practice}/tournament/Tournament.cs (100%)
 rename exercises/{ => practice}/tournament/Tournament.csproj (100%)
 rename exercises/{ => practice}/tournament/TournamentTests.cs (100%)
 rename exercises/{ => practice}/transpose/.editorconfig (100%)
 rename exercises/{ => practice}/transpose/.meta/tests.toml (100%)
 rename exercises/{ => practice}/transpose/Example.cs (100%)
 rename exercises/{ => practice}/transpose/README.md (100%)
 rename exercises/{ => practice}/transpose/Transpose.cs (100%)
 rename exercises/{ => practice}/transpose/Transpose.csproj (100%)
 rename exercises/{ => practice}/transpose/TransposeTests.cs (100%)
 rename exercises/{ => practice}/tree-building/.editorconfig (100%)
 rename exercises/{ => practice}/tree-building/Example.cs (100%)
 rename exercises/{ => practice}/tree-building/README.md (100%)
 rename exercises/{ => practice}/tree-building/TreeBuilding.cs (100%)
 rename exercises/{ => practice}/tree-building/TreeBuilding.csproj (100%)
 rename exercises/{ => practice}/tree-building/TreeBuildingTests.cs (100%)
 rename exercises/{ => practice}/triangle/.editorconfig (100%)
 rename exercises/{ => practice}/triangle/.meta/tests.toml (100%)
 rename exercises/{ => practice}/triangle/Example.cs (100%)
 rename exercises/{ => practice}/triangle/README.md (100%)
 rename exercises/{ => practice}/triangle/Triangle.cs (100%)
 rename exercises/{ => practice}/triangle/Triangle.csproj (100%)
 rename exercises/{ => practice}/triangle/TriangleTests.cs (100%)
 rename exercises/{ => practice}/trinary/.editorconfig (100%)
 rename exercises/{ => practice}/trinary/.meta/tests.toml (100%)
 rename exercises/{ => practice}/trinary/Example.cs (100%)
 rename exercises/{ => practice}/trinary/README.md (100%)
 rename exercises/{ => practice}/trinary/Trinary.cs (100%)
 rename exercises/{ => practice}/trinary/Trinary.csproj (100%)
 rename exercises/{ => practice}/trinary/TrinaryTests.cs (100%)
 rename exercises/{ => practice}/twelve-days/.editorconfig (100%)
 rename exercises/{ => practice}/twelve-days/.meta/hints.md (100%)
 rename exercises/{ => practice}/twelve-days/.meta/tests.toml (100%)
 rename exercises/{ => practice}/twelve-days/Example.cs (100%)
 rename exercises/{ => practice}/twelve-days/README.md (100%)
 rename exercises/{ => practice}/twelve-days/TwelveDays.cs (100%)
 rename exercises/{ => practice}/twelve-days/TwelveDays.csproj (100%)
 rename exercises/{ => practice}/twelve-days/TwelveDaysTests.cs (100%)
 rename exercises/{ => practice}/two-bucket/.editorconfig (100%)
 rename exercises/{ => practice}/two-bucket/.meta/tests.toml (100%)
 rename exercises/{ => practice}/two-bucket/Example.cs (100%)
 rename exercises/{ => practice}/two-bucket/README.md (100%)
 rename exercises/{ => practice}/two-bucket/TwoBucket.cs (100%)
 rename exercises/{ => practice}/two-bucket/TwoBucket.csproj (100%)
 rename exercises/{ => practice}/two-bucket/TwoBucketTests.cs (100%)
 rename exercises/{ => practice}/two-fer/.editorconfig (100%)
 rename exercises/{ => practice}/two-fer/.meta/tests.toml (100%)
 rename exercises/{ => practice}/two-fer/Example.cs (100%)
 rename exercises/{ => practice}/two-fer/README.md (100%)
 rename exercises/{ => practice}/two-fer/TwoFer.cs (100%)
 rename exercises/{ => practice}/two-fer/TwoFer.csproj (100%)
 rename exercises/{ => practice}/two-fer/TwoFerTests.cs (100%)
 rename exercises/{ => practice}/variable-length-quantity/.editorconfig (100%)
 rename exercises/{ => practice}/variable-length-quantity/.meta/hints.md (100%)
 rename exercises/{ => practice}/variable-length-quantity/.meta/tests.toml (100%)
 rename exercises/{ => practice}/variable-length-quantity/Example.cs (100%)
 rename exercises/{ => practice}/variable-length-quantity/README.md (100%)
 rename exercises/{ => practice}/variable-length-quantity/VariableLengthQuantity.cs (100%)
 rename exercises/{ => practice}/variable-length-quantity/VariableLengthQuantity.csproj (100%)
 rename exercises/{ => practice}/variable-length-quantity/VariableLengthQuantityTests.cs (100%)
 rename exercises/{ => practice}/word-count/.editorconfig (100%)
 rename exercises/{ => practice}/word-count/.meta/tests.toml (100%)
 rename exercises/{ => practice}/word-count/Example.cs (100%)
 rename exercises/{ => practice}/word-count/README.md (100%)
 rename exercises/{ => practice}/word-count/WordCount.cs (100%)
 rename exercises/{ => practice}/word-count/WordCount.csproj (100%)
 rename exercises/{ => practice}/word-count/WordCountTests.cs (100%)
 rename exercises/{ => practice}/word-search/.editorconfig (100%)
 rename exercises/{ => practice}/word-search/.meta/hints.md (100%)
 rename exercises/{ => practice}/word-search/.meta/tests.toml (100%)
 rename exercises/{ => practice}/word-search/Example.cs (100%)
 rename exercises/{ => practice}/word-search/README.md (100%)
 rename exercises/{ => practice}/word-search/WordSearch.cs (100%)
 rename exercises/{ => practice}/word-search/WordSearch.csproj (100%)
 rename exercises/{ => practice}/word-search/WordSearchTests.cs (100%)
 rename exercises/{ => practice}/wordy/.editorconfig (100%)
 rename exercises/{ => practice}/wordy/.meta/hints.md (100%)
 rename exercises/{ => practice}/wordy/.meta/tests.toml (100%)
 rename exercises/{ => practice}/wordy/Example.cs (100%)
 rename exercises/{ => practice}/wordy/README.md (100%)
 rename exercises/{ => practice}/wordy/Wordy.cs (100%)
 rename exercises/{ => practice}/wordy/Wordy.csproj (100%)
 rename exercises/{ => practice}/wordy/WordyTests.cs (100%)
 rename exercises/{ => practice}/yacht/.editorconfig (100%)
 rename exercises/{ => practice}/yacht/.meta/tests.toml (100%)
 rename exercises/{ => practice}/yacht/Example.cs (100%)
 rename exercises/{ => practice}/yacht/README.md (100%)
 rename exercises/{ => practice}/yacht/Yacht.cs (100%)
 rename exercises/{ => practice}/yacht/Yacht.csproj (100%)
 rename exercises/{ => practice}/yacht/YachtTests.cs (100%)
 rename exercises/{ => practice}/zebra-puzzle/.editorconfig (100%)
 rename exercises/{ => practice}/zebra-puzzle/.meta/hints.md (100%)
 rename exercises/{ => practice}/zebra-puzzle/.meta/tests.toml (100%)
 rename exercises/{ => practice}/zebra-puzzle/Example.cs (100%)
 rename exercises/{ => practice}/zebra-puzzle/README.md (100%)
 rename exercises/{ => practice}/zebra-puzzle/ZebraPuzzle.cs (100%)
 rename exercises/{ => practice}/zebra-puzzle/ZebraPuzzle.csproj (100%)
 rename exercises/{ => practice}/zebra-puzzle/ZebraPuzzleTests.cs (100%)
 rename exercises/{ => practice}/zipper/.editorconfig (100%)
 rename exercises/{ => practice}/zipper/.meta/hints.md (100%)
 rename exercises/{ => practice}/zipper/.meta/tests.toml (100%)
 rename exercises/{ => practice}/zipper/Example.cs (100%)
 rename exercises/{ => practice}/zipper/README.md (100%)
 rename exercises/{ => practice}/zipper/Zipper.cs (100%)
 rename exercises/{ => practice}/zipper/Zipper.csproj (100%)
 rename exercises/{ => practice}/zipper/ZipperTests.cs (100%)

diff --git a/exercises/accumulate/.editorconfig b/exercises/practice/accumulate/.editorconfig
similarity index 100%
rename from exercises/accumulate/.editorconfig
rename to exercises/practice/accumulate/.editorconfig
diff --git a/exercises/accumulate/.meta/hints.md b/exercises/practice/accumulate/.meta/hints.md
similarity index 100%
rename from exercises/accumulate/.meta/hints.md
rename to exercises/practice/accumulate/.meta/hints.md
diff --git a/exercises/accumulate/Accumulate.cs b/exercises/practice/accumulate/Accumulate.cs
similarity index 100%
rename from exercises/accumulate/Accumulate.cs
rename to exercises/practice/accumulate/Accumulate.cs
diff --git a/exercises/accumulate/Accumulate.csproj b/exercises/practice/accumulate/Accumulate.csproj
similarity index 100%
rename from exercises/accumulate/Accumulate.csproj
rename to exercises/practice/accumulate/Accumulate.csproj
diff --git a/exercises/accumulate/AccumulateTests.cs b/exercises/practice/accumulate/AccumulateTests.cs
similarity index 100%
rename from exercises/accumulate/AccumulateTests.cs
rename to exercises/practice/accumulate/AccumulateTests.cs
diff --git a/exercises/accumulate/Example.cs b/exercises/practice/accumulate/Example.cs
similarity index 100%
rename from exercises/accumulate/Example.cs
rename to exercises/practice/accumulate/Example.cs
diff --git a/exercises/accumulate/README.md b/exercises/practice/accumulate/README.md
similarity index 100%
rename from exercises/accumulate/README.md
rename to exercises/practice/accumulate/README.md
diff --git a/exercises/acronym/.editorconfig b/exercises/practice/acronym/.editorconfig
similarity index 100%
rename from exercises/acronym/.editorconfig
rename to exercises/practice/acronym/.editorconfig
diff --git a/exercises/acronym/.meta/tests.toml b/exercises/practice/acronym/.meta/tests.toml
similarity index 100%
rename from exercises/acronym/.meta/tests.toml
rename to exercises/practice/acronym/.meta/tests.toml
diff --git a/exercises/acronym/Acronym.cs b/exercises/practice/acronym/Acronym.cs
similarity index 100%
rename from exercises/acronym/Acronym.cs
rename to exercises/practice/acronym/Acronym.cs
diff --git a/exercises/acronym/Acronym.csproj b/exercises/practice/acronym/Acronym.csproj
similarity index 100%
rename from exercises/acronym/Acronym.csproj
rename to exercises/practice/acronym/Acronym.csproj
diff --git a/exercises/acronym/AcronymTests.cs b/exercises/practice/acronym/AcronymTests.cs
similarity index 100%
rename from exercises/acronym/AcronymTests.cs
rename to exercises/practice/acronym/AcronymTests.cs
diff --git a/exercises/acronym/Example.cs b/exercises/practice/acronym/Example.cs
similarity index 100%
rename from exercises/acronym/Example.cs
rename to exercises/practice/acronym/Example.cs
diff --git a/exercises/acronym/README.md b/exercises/practice/acronym/README.md
similarity index 100%
rename from exercises/acronym/README.md
rename to exercises/practice/acronym/README.md
diff --git a/exercises/affine-cipher/.editorconfig b/exercises/practice/affine-cipher/.editorconfig
similarity index 100%
rename from exercises/affine-cipher/.editorconfig
rename to exercises/practice/affine-cipher/.editorconfig
diff --git a/exercises/affine-cipher/.meta/tests.toml b/exercises/practice/affine-cipher/.meta/tests.toml
similarity index 100%
rename from exercises/affine-cipher/.meta/tests.toml
rename to exercises/practice/affine-cipher/.meta/tests.toml
diff --git a/exercises/affine-cipher/AffineCipher.cs b/exercises/practice/affine-cipher/AffineCipher.cs
similarity index 100%
rename from exercises/affine-cipher/AffineCipher.cs
rename to exercises/practice/affine-cipher/AffineCipher.cs
diff --git a/exercises/affine-cipher/AffineCipher.csproj b/exercises/practice/affine-cipher/AffineCipher.csproj
similarity index 100%
rename from exercises/affine-cipher/AffineCipher.csproj
rename to exercises/practice/affine-cipher/AffineCipher.csproj
diff --git a/exercises/affine-cipher/AffineCipherTests.cs b/exercises/practice/affine-cipher/AffineCipherTests.cs
similarity index 100%
rename from exercises/affine-cipher/AffineCipherTests.cs
rename to exercises/practice/affine-cipher/AffineCipherTests.cs
diff --git a/exercises/affine-cipher/Example.cs b/exercises/practice/affine-cipher/Example.cs
similarity index 100%
rename from exercises/affine-cipher/Example.cs
rename to exercises/practice/affine-cipher/Example.cs
diff --git a/exercises/affine-cipher/README.md b/exercises/practice/affine-cipher/README.md
similarity index 100%
rename from exercises/affine-cipher/README.md
rename to exercises/practice/affine-cipher/README.md
diff --git a/exercises/all-your-base/.editorconfig b/exercises/practice/all-your-base/.editorconfig
similarity index 100%
rename from exercises/all-your-base/.editorconfig
rename to exercises/practice/all-your-base/.editorconfig
diff --git a/exercises/all-your-base/.meta/tests.toml b/exercises/practice/all-your-base/.meta/tests.toml
similarity index 100%
rename from exercises/all-your-base/.meta/tests.toml
rename to exercises/practice/all-your-base/.meta/tests.toml
diff --git a/exercises/all-your-base/AllYourBase.cs b/exercises/practice/all-your-base/AllYourBase.cs
similarity index 100%
rename from exercises/all-your-base/AllYourBase.cs
rename to exercises/practice/all-your-base/AllYourBase.cs
diff --git a/exercises/all-your-base/AllYourBase.csproj b/exercises/practice/all-your-base/AllYourBase.csproj
similarity index 100%
rename from exercises/all-your-base/AllYourBase.csproj
rename to exercises/practice/all-your-base/AllYourBase.csproj
diff --git a/exercises/all-your-base/AllYourBaseTests.cs b/exercises/practice/all-your-base/AllYourBaseTests.cs
similarity index 100%
rename from exercises/all-your-base/AllYourBaseTests.cs
rename to exercises/practice/all-your-base/AllYourBaseTests.cs
diff --git a/exercises/all-your-base/Example.cs b/exercises/practice/all-your-base/Example.cs
similarity index 100%
rename from exercises/all-your-base/Example.cs
rename to exercises/practice/all-your-base/Example.cs
diff --git a/exercises/all-your-base/README.md b/exercises/practice/all-your-base/README.md
similarity index 100%
rename from exercises/all-your-base/README.md
rename to exercises/practice/all-your-base/README.md
diff --git a/exercises/allergies/.editorconfig b/exercises/practice/allergies/.editorconfig
similarity index 100%
rename from exercises/allergies/.editorconfig
rename to exercises/practice/allergies/.editorconfig
diff --git a/exercises/allergies/.meta/hints.md b/exercises/practice/allergies/.meta/hints.md
similarity index 100%
rename from exercises/allergies/.meta/hints.md
rename to exercises/practice/allergies/.meta/hints.md
diff --git a/exercises/allergies/.meta/tests.toml b/exercises/practice/allergies/.meta/tests.toml
similarity index 100%
rename from exercises/allergies/.meta/tests.toml
rename to exercises/practice/allergies/.meta/tests.toml
diff --git a/exercises/allergies/Allergies.cs b/exercises/practice/allergies/Allergies.cs
similarity index 100%
rename from exercises/allergies/Allergies.cs
rename to exercises/practice/allergies/Allergies.cs
diff --git a/exercises/allergies/Allergies.csproj b/exercises/practice/allergies/Allergies.csproj
similarity index 100%
rename from exercises/allergies/Allergies.csproj
rename to exercises/practice/allergies/Allergies.csproj
diff --git a/exercises/allergies/AllergiesTests.cs b/exercises/practice/allergies/AllergiesTests.cs
similarity index 100%
rename from exercises/allergies/AllergiesTests.cs
rename to exercises/practice/allergies/AllergiesTests.cs
diff --git a/exercises/allergies/Example.cs b/exercises/practice/allergies/Example.cs
similarity index 100%
rename from exercises/allergies/Example.cs
rename to exercises/practice/allergies/Example.cs
diff --git a/exercises/allergies/README.md b/exercises/practice/allergies/README.md
similarity index 100%
rename from exercises/allergies/README.md
rename to exercises/practice/allergies/README.md
diff --git a/exercises/alphametics/.editorconfig b/exercises/practice/alphametics/.editorconfig
similarity index 100%
rename from exercises/alphametics/.editorconfig
rename to exercises/practice/alphametics/.editorconfig
diff --git a/exercises/alphametics/.meta/hints.md b/exercises/practice/alphametics/.meta/hints.md
similarity index 100%
rename from exercises/alphametics/.meta/hints.md
rename to exercises/practice/alphametics/.meta/hints.md
diff --git a/exercises/alphametics/.meta/tests.toml b/exercises/practice/alphametics/.meta/tests.toml
similarity index 100%
rename from exercises/alphametics/.meta/tests.toml
rename to exercises/practice/alphametics/.meta/tests.toml
diff --git a/exercises/alphametics/Alphametics.cs b/exercises/practice/alphametics/Alphametics.cs
similarity index 100%
rename from exercises/alphametics/Alphametics.cs
rename to exercises/practice/alphametics/Alphametics.cs
diff --git a/exercises/alphametics/Alphametics.csproj b/exercises/practice/alphametics/Alphametics.csproj
similarity index 100%
rename from exercises/alphametics/Alphametics.csproj
rename to exercises/practice/alphametics/Alphametics.csproj
diff --git a/exercises/alphametics/AlphameticsTests.cs b/exercises/practice/alphametics/AlphameticsTests.cs
similarity index 100%
rename from exercises/alphametics/AlphameticsTests.cs
rename to exercises/practice/alphametics/AlphameticsTests.cs
diff --git a/exercises/alphametics/Example.cs b/exercises/practice/alphametics/Example.cs
similarity index 100%
rename from exercises/alphametics/Example.cs
rename to exercises/practice/alphametics/Example.cs
diff --git a/exercises/alphametics/README.md b/exercises/practice/alphametics/README.md
similarity index 100%
rename from exercises/alphametics/README.md
rename to exercises/practice/alphametics/README.md
diff --git a/exercises/anagram/.editorconfig b/exercises/practice/anagram/.editorconfig
similarity index 100%
rename from exercises/anagram/.editorconfig
rename to exercises/practice/anagram/.editorconfig
diff --git a/exercises/anagram/.meta/tests.toml b/exercises/practice/anagram/.meta/tests.toml
similarity index 100%
rename from exercises/anagram/.meta/tests.toml
rename to exercises/practice/anagram/.meta/tests.toml
diff --git a/exercises/anagram/Anagram.cs b/exercises/practice/anagram/Anagram.cs
similarity index 100%
rename from exercises/anagram/Anagram.cs
rename to exercises/practice/anagram/Anagram.cs
diff --git a/exercises/anagram/Anagram.csproj b/exercises/practice/anagram/Anagram.csproj
similarity index 100%
rename from exercises/anagram/Anagram.csproj
rename to exercises/practice/anagram/Anagram.csproj
diff --git a/exercises/anagram/AnagramTests.cs b/exercises/practice/anagram/AnagramTests.cs
similarity index 100%
rename from exercises/anagram/AnagramTests.cs
rename to exercises/practice/anagram/AnagramTests.cs
diff --git a/exercises/anagram/Example.cs b/exercises/practice/anagram/Example.cs
similarity index 100%
rename from exercises/anagram/Example.cs
rename to exercises/practice/anagram/Example.cs
diff --git a/exercises/anagram/README.md b/exercises/practice/anagram/README.md
similarity index 100%
rename from exercises/anagram/README.md
rename to exercises/practice/anagram/README.md
diff --git a/exercises/armstrong-numbers/.editorconfig b/exercises/practice/armstrong-numbers/.editorconfig
similarity index 100%
rename from exercises/armstrong-numbers/.editorconfig
rename to exercises/practice/armstrong-numbers/.editorconfig
diff --git a/exercises/armstrong-numbers/.meta/tests.toml b/exercises/practice/armstrong-numbers/.meta/tests.toml
similarity index 100%
rename from exercises/armstrong-numbers/.meta/tests.toml
rename to exercises/practice/armstrong-numbers/.meta/tests.toml
diff --git a/exercises/armstrong-numbers/ArmstrongNumbers.cs b/exercises/practice/armstrong-numbers/ArmstrongNumbers.cs
similarity index 100%
rename from exercises/armstrong-numbers/ArmstrongNumbers.cs
rename to exercises/practice/armstrong-numbers/ArmstrongNumbers.cs
diff --git a/exercises/armstrong-numbers/ArmstrongNumbers.csproj b/exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj
similarity index 100%
rename from exercises/armstrong-numbers/ArmstrongNumbers.csproj
rename to exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj
diff --git a/exercises/armstrong-numbers/ArmstrongNumbersTests.cs b/exercises/practice/armstrong-numbers/ArmstrongNumbersTests.cs
similarity index 100%
rename from exercises/armstrong-numbers/ArmstrongNumbersTests.cs
rename to exercises/practice/armstrong-numbers/ArmstrongNumbersTests.cs
diff --git a/exercises/armstrong-numbers/Example.cs b/exercises/practice/armstrong-numbers/Example.cs
similarity index 100%
rename from exercises/armstrong-numbers/Example.cs
rename to exercises/practice/armstrong-numbers/Example.cs
diff --git a/exercises/armstrong-numbers/README.md b/exercises/practice/armstrong-numbers/README.md
similarity index 100%
rename from exercises/armstrong-numbers/README.md
rename to exercises/practice/armstrong-numbers/README.md
diff --git a/exercises/atbash-cipher/.editorconfig b/exercises/practice/atbash-cipher/.editorconfig
similarity index 100%
rename from exercises/atbash-cipher/.editorconfig
rename to exercises/practice/atbash-cipher/.editorconfig
diff --git a/exercises/atbash-cipher/.meta/tests.toml b/exercises/practice/atbash-cipher/.meta/tests.toml
similarity index 100%
rename from exercises/atbash-cipher/.meta/tests.toml
rename to exercises/practice/atbash-cipher/.meta/tests.toml
diff --git a/exercises/atbash-cipher/AtbashCipher.cs b/exercises/practice/atbash-cipher/AtbashCipher.cs
similarity index 100%
rename from exercises/atbash-cipher/AtbashCipher.cs
rename to exercises/practice/atbash-cipher/AtbashCipher.cs
diff --git a/exercises/atbash-cipher/AtbashCipher.csproj b/exercises/practice/atbash-cipher/AtbashCipher.csproj
similarity index 100%
rename from exercises/atbash-cipher/AtbashCipher.csproj
rename to exercises/practice/atbash-cipher/AtbashCipher.csproj
diff --git a/exercises/atbash-cipher/AtbashCipherTests.cs b/exercises/practice/atbash-cipher/AtbashCipherTests.cs
similarity index 100%
rename from exercises/atbash-cipher/AtbashCipherTests.cs
rename to exercises/practice/atbash-cipher/AtbashCipherTests.cs
diff --git a/exercises/atbash-cipher/Example.cs b/exercises/practice/atbash-cipher/Example.cs
similarity index 100%
rename from exercises/atbash-cipher/Example.cs
rename to exercises/practice/atbash-cipher/Example.cs
diff --git a/exercises/atbash-cipher/README.md b/exercises/practice/atbash-cipher/README.md
similarity index 100%
rename from exercises/atbash-cipher/README.md
rename to exercises/practice/atbash-cipher/README.md
diff --git a/exercises/bank-account/.editorconfig b/exercises/practice/bank-account/.editorconfig
similarity index 100%
rename from exercises/bank-account/.editorconfig
rename to exercises/practice/bank-account/.editorconfig
diff --git a/exercises/bank-account/.meta/hints.md b/exercises/practice/bank-account/.meta/hints.md
similarity index 100%
rename from exercises/bank-account/.meta/hints.md
rename to exercises/practice/bank-account/.meta/hints.md
diff --git a/exercises/bank-account/BankAccount.cs b/exercises/practice/bank-account/BankAccount.cs
similarity index 100%
rename from exercises/bank-account/BankAccount.cs
rename to exercises/practice/bank-account/BankAccount.cs
diff --git a/exercises/bank-account/BankAccount.csproj b/exercises/practice/bank-account/BankAccount.csproj
similarity index 100%
rename from exercises/bank-account/BankAccount.csproj
rename to exercises/practice/bank-account/BankAccount.csproj
diff --git a/exercises/bank-account/BankAccountTests.cs b/exercises/practice/bank-account/BankAccountTests.cs
similarity index 100%
rename from exercises/bank-account/BankAccountTests.cs
rename to exercises/practice/bank-account/BankAccountTests.cs
diff --git a/exercises/bank-account/Example.cs b/exercises/practice/bank-account/Example.cs
similarity index 100%
rename from exercises/bank-account/Example.cs
rename to exercises/practice/bank-account/Example.cs
diff --git a/exercises/bank-account/README.md b/exercises/practice/bank-account/README.md
similarity index 100%
rename from exercises/bank-account/README.md
rename to exercises/practice/bank-account/README.md
diff --git a/exercises/beer-song/.editorconfig b/exercises/practice/beer-song/.editorconfig
similarity index 100%
rename from exercises/beer-song/.editorconfig
rename to exercises/practice/beer-song/.editorconfig
diff --git a/exercises/beer-song/.meta/hints.md b/exercises/practice/beer-song/.meta/hints.md
similarity index 100%
rename from exercises/beer-song/.meta/hints.md
rename to exercises/practice/beer-song/.meta/hints.md
diff --git a/exercises/beer-song/.meta/tests.toml b/exercises/practice/beer-song/.meta/tests.toml
similarity index 100%
rename from exercises/beer-song/.meta/tests.toml
rename to exercises/practice/beer-song/.meta/tests.toml
diff --git a/exercises/beer-song/BeerSong.cs b/exercises/practice/beer-song/BeerSong.cs
similarity index 100%
rename from exercises/beer-song/BeerSong.cs
rename to exercises/practice/beer-song/BeerSong.cs
diff --git a/exercises/beer-song/BeerSong.csproj b/exercises/practice/beer-song/BeerSong.csproj
similarity index 100%
rename from exercises/beer-song/BeerSong.csproj
rename to exercises/practice/beer-song/BeerSong.csproj
diff --git a/exercises/beer-song/BeerSongTests.cs b/exercises/practice/beer-song/BeerSongTests.cs
similarity index 100%
rename from exercises/beer-song/BeerSongTests.cs
rename to exercises/practice/beer-song/BeerSongTests.cs
diff --git a/exercises/beer-song/Example.cs b/exercises/practice/beer-song/Example.cs
similarity index 100%
rename from exercises/beer-song/Example.cs
rename to exercises/practice/beer-song/Example.cs
diff --git a/exercises/beer-song/README.md b/exercises/practice/beer-song/README.md
similarity index 100%
rename from exercises/beer-song/README.md
rename to exercises/practice/beer-song/README.md
diff --git a/exercises/binary-search-tree/.editorconfig b/exercises/practice/binary-search-tree/.editorconfig
similarity index 100%
rename from exercises/binary-search-tree/.editorconfig
rename to exercises/practice/binary-search-tree/.editorconfig
diff --git a/exercises/binary-search-tree/.meta/tests.toml b/exercises/practice/binary-search-tree/.meta/tests.toml
similarity index 100%
rename from exercises/binary-search-tree/.meta/tests.toml
rename to exercises/practice/binary-search-tree/.meta/tests.toml
diff --git a/exercises/binary-search-tree/BinarySearchTree.cs b/exercises/practice/binary-search-tree/BinarySearchTree.cs
similarity index 100%
rename from exercises/binary-search-tree/BinarySearchTree.cs
rename to exercises/practice/binary-search-tree/BinarySearchTree.cs
diff --git a/exercises/binary-search-tree/BinarySearchTree.csproj b/exercises/practice/binary-search-tree/BinarySearchTree.csproj
similarity index 100%
rename from exercises/binary-search-tree/BinarySearchTree.csproj
rename to exercises/practice/binary-search-tree/BinarySearchTree.csproj
diff --git a/exercises/binary-search-tree/BinarySearchTreeTests.cs b/exercises/practice/binary-search-tree/BinarySearchTreeTests.cs
similarity index 100%
rename from exercises/binary-search-tree/BinarySearchTreeTests.cs
rename to exercises/practice/binary-search-tree/BinarySearchTreeTests.cs
diff --git a/exercises/binary-search-tree/Example.cs b/exercises/practice/binary-search-tree/Example.cs
similarity index 100%
rename from exercises/binary-search-tree/Example.cs
rename to exercises/practice/binary-search-tree/Example.cs
diff --git a/exercises/binary-search-tree/README.md b/exercises/practice/binary-search-tree/README.md
similarity index 100%
rename from exercises/binary-search-tree/README.md
rename to exercises/practice/binary-search-tree/README.md
diff --git a/exercises/binary-search/.editorconfig b/exercises/practice/binary-search/.editorconfig
similarity index 100%
rename from exercises/binary-search/.editorconfig
rename to exercises/practice/binary-search/.editorconfig
diff --git a/exercises/binary-search/.meta/tests.toml b/exercises/practice/binary-search/.meta/tests.toml
similarity index 100%
rename from exercises/binary-search/.meta/tests.toml
rename to exercises/practice/binary-search/.meta/tests.toml
diff --git a/exercises/binary-search/BinarySearch.cs b/exercises/practice/binary-search/BinarySearch.cs
similarity index 100%
rename from exercises/binary-search/BinarySearch.cs
rename to exercises/practice/binary-search/BinarySearch.cs
diff --git a/exercises/binary-search/BinarySearch.csproj b/exercises/practice/binary-search/BinarySearch.csproj
similarity index 100%
rename from exercises/binary-search/BinarySearch.csproj
rename to exercises/practice/binary-search/BinarySearch.csproj
diff --git a/exercises/binary-search/BinarySearchTests.cs b/exercises/practice/binary-search/BinarySearchTests.cs
similarity index 100%
rename from exercises/binary-search/BinarySearchTests.cs
rename to exercises/practice/binary-search/BinarySearchTests.cs
diff --git a/exercises/binary-search/Example.cs b/exercises/practice/binary-search/Example.cs
similarity index 100%
rename from exercises/binary-search/Example.cs
rename to exercises/practice/binary-search/Example.cs
diff --git a/exercises/binary-search/README.md b/exercises/practice/binary-search/README.md
similarity index 100%
rename from exercises/binary-search/README.md
rename to exercises/practice/binary-search/README.md
diff --git a/exercises/binary/.editorconfig b/exercises/practice/binary/.editorconfig
similarity index 100%
rename from exercises/binary/.editorconfig
rename to exercises/practice/binary/.editorconfig
diff --git a/exercises/binary/.meta/tests.toml b/exercises/practice/binary/.meta/tests.toml
similarity index 100%
rename from exercises/binary/.meta/tests.toml
rename to exercises/practice/binary/.meta/tests.toml
diff --git a/exercises/binary/Binary.cs b/exercises/practice/binary/Binary.cs
similarity index 100%
rename from exercises/binary/Binary.cs
rename to exercises/practice/binary/Binary.cs
diff --git a/exercises/binary/Binary.csproj b/exercises/practice/binary/Binary.csproj
similarity index 100%
rename from exercises/binary/Binary.csproj
rename to exercises/practice/binary/Binary.csproj
diff --git a/exercises/binary/BinaryTests.cs b/exercises/practice/binary/BinaryTests.cs
similarity index 100%
rename from exercises/binary/BinaryTests.cs
rename to exercises/practice/binary/BinaryTests.cs
diff --git a/exercises/binary/Example.cs b/exercises/practice/binary/Example.cs
similarity index 100%
rename from exercises/binary/Example.cs
rename to exercises/practice/binary/Example.cs
diff --git a/exercises/binary/README.md b/exercises/practice/binary/README.md
similarity index 100%
rename from exercises/binary/README.md
rename to exercises/practice/binary/README.md
diff --git a/exercises/bob/.editorconfig b/exercises/practice/bob/.editorconfig
similarity index 100%
rename from exercises/bob/.editorconfig
rename to exercises/practice/bob/.editorconfig
diff --git a/exercises/bob/.meta/tests.toml b/exercises/practice/bob/.meta/tests.toml
similarity index 100%
rename from exercises/bob/.meta/tests.toml
rename to exercises/practice/bob/.meta/tests.toml
diff --git a/exercises/bob/Bob.cs b/exercises/practice/bob/Bob.cs
similarity index 100%
rename from exercises/bob/Bob.cs
rename to exercises/practice/bob/Bob.cs
diff --git a/exercises/bob/Bob.csproj b/exercises/practice/bob/Bob.csproj
similarity index 100%
rename from exercises/bob/Bob.csproj
rename to exercises/practice/bob/Bob.csproj
diff --git a/exercises/bob/BobTests.cs b/exercises/practice/bob/BobTests.cs
similarity index 100%
rename from exercises/bob/BobTests.cs
rename to exercises/practice/bob/BobTests.cs
diff --git a/exercises/bob/Example.cs b/exercises/practice/bob/Example.cs
similarity index 100%
rename from exercises/bob/Example.cs
rename to exercises/practice/bob/Example.cs
diff --git a/exercises/bob/README.md b/exercises/practice/bob/README.md
similarity index 100%
rename from exercises/bob/README.md
rename to exercises/practice/bob/README.md
diff --git a/exercises/book-store/.editorconfig b/exercises/practice/book-store/.editorconfig
similarity index 100%
rename from exercises/book-store/.editorconfig
rename to exercises/practice/book-store/.editorconfig
diff --git a/exercises/book-store/.meta/tests.toml b/exercises/practice/book-store/.meta/tests.toml
similarity index 100%
rename from exercises/book-store/.meta/tests.toml
rename to exercises/practice/book-store/.meta/tests.toml
diff --git a/exercises/book-store/BookStore.cs b/exercises/practice/book-store/BookStore.cs
similarity index 100%
rename from exercises/book-store/BookStore.cs
rename to exercises/practice/book-store/BookStore.cs
diff --git a/exercises/book-store/BookStore.csproj b/exercises/practice/book-store/BookStore.csproj
similarity index 100%
rename from exercises/book-store/BookStore.csproj
rename to exercises/practice/book-store/BookStore.csproj
diff --git a/exercises/book-store/BookStoreTests.cs b/exercises/practice/book-store/BookStoreTests.cs
similarity index 100%
rename from exercises/book-store/BookStoreTests.cs
rename to exercises/practice/book-store/BookStoreTests.cs
diff --git a/exercises/book-store/Example.cs b/exercises/practice/book-store/Example.cs
similarity index 100%
rename from exercises/book-store/Example.cs
rename to exercises/practice/book-store/Example.cs
diff --git a/exercises/book-store/README.md b/exercises/practice/book-store/README.md
similarity index 100%
rename from exercises/book-store/README.md
rename to exercises/practice/book-store/README.md
diff --git a/exercises/bowling/.editorconfig b/exercises/practice/bowling/.editorconfig
similarity index 100%
rename from exercises/bowling/.editorconfig
rename to exercises/practice/bowling/.editorconfig
diff --git a/exercises/bowling/.meta/tests.toml b/exercises/practice/bowling/.meta/tests.toml
similarity index 100%
rename from exercises/bowling/.meta/tests.toml
rename to exercises/practice/bowling/.meta/tests.toml
diff --git a/exercises/bowling/Bowling.cs b/exercises/practice/bowling/Bowling.cs
similarity index 100%
rename from exercises/bowling/Bowling.cs
rename to exercises/practice/bowling/Bowling.cs
diff --git a/exercises/bowling/Bowling.csproj b/exercises/practice/bowling/Bowling.csproj
similarity index 100%
rename from exercises/bowling/Bowling.csproj
rename to exercises/practice/bowling/Bowling.csproj
diff --git a/exercises/bowling/BowlingTests.cs b/exercises/practice/bowling/BowlingTests.cs
similarity index 100%
rename from exercises/bowling/BowlingTests.cs
rename to exercises/practice/bowling/BowlingTests.cs
diff --git a/exercises/bowling/Example.cs b/exercises/practice/bowling/Example.cs
similarity index 100%
rename from exercises/bowling/Example.cs
rename to exercises/practice/bowling/Example.cs
diff --git a/exercises/bowling/README.md b/exercises/practice/bowling/README.md
similarity index 100%
rename from exercises/bowling/README.md
rename to exercises/practice/bowling/README.md
diff --git a/exercises/change/.editorconfig b/exercises/practice/change/.editorconfig
similarity index 100%
rename from exercises/change/.editorconfig
rename to exercises/practice/change/.editorconfig
diff --git a/exercises/change/.meta/tests.toml b/exercises/practice/change/.meta/tests.toml
similarity index 100%
rename from exercises/change/.meta/tests.toml
rename to exercises/practice/change/.meta/tests.toml
diff --git a/exercises/change/Change.cs b/exercises/practice/change/Change.cs
similarity index 100%
rename from exercises/change/Change.cs
rename to exercises/practice/change/Change.cs
diff --git a/exercises/change/Change.csproj b/exercises/practice/change/Change.csproj
similarity index 100%
rename from exercises/change/Change.csproj
rename to exercises/practice/change/Change.csproj
diff --git a/exercises/change/ChangeTests.cs b/exercises/practice/change/ChangeTests.cs
similarity index 100%
rename from exercises/change/ChangeTests.cs
rename to exercises/practice/change/ChangeTests.cs
diff --git a/exercises/change/Example.cs b/exercises/practice/change/Example.cs
similarity index 100%
rename from exercises/change/Example.cs
rename to exercises/practice/change/Example.cs
diff --git a/exercises/change/README.md b/exercises/practice/change/README.md
similarity index 100%
rename from exercises/change/README.md
rename to exercises/practice/change/README.md
diff --git a/exercises/circular-buffer/.editorconfig b/exercises/practice/circular-buffer/.editorconfig
similarity index 100%
rename from exercises/circular-buffer/.editorconfig
rename to exercises/practice/circular-buffer/.editorconfig
diff --git a/exercises/circular-buffer/.meta/tests.toml b/exercises/practice/circular-buffer/.meta/tests.toml
similarity index 100%
rename from exercises/circular-buffer/.meta/tests.toml
rename to exercises/practice/circular-buffer/.meta/tests.toml
diff --git a/exercises/circular-buffer/CircularBuffer.cs b/exercises/practice/circular-buffer/CircularBuffer.cs
similarity index 100%
rename from exercises/circular-buffer/CircularBuffer.cs
rename to exercises/practice/circular-buffer/CircularBuffer.cs
diff --git a/exercises/circular-buffer/CircularBuffer.csproj b/exercises/practice/circular-buffer/CircularBuffer.csproj
similarity index 100%
rename from exercises/circular-buffer/CircularBuffer.csproj
rename to exercises/practice/circular-buffer/CircularBuffer.csproj
diff --git a/exercises/circular-buffer/CircularBufferTests.cs b/exercises/practice/circular-buffer/CircularBufferTests.cs
similarity index 100%
rename from exercises/circular-buffer/CircularBufferTests.cs
rename to exercises/practice/circular-buffer/CircularBufferTests.cs
diff --git a/exercises/circular-buffer/Example.cs b/exercises/practice/circular-buffer/Example.cs
similarity index 100%
rename from exercises/circular-buffer/Example.cs
rename to exercises/practice/circular-buffer/Example.cs
diff --git a/exercises/circular-buffer/README.md b/exercises/practice/circular-buffer/README.md
similarity index 100%
rename from exercises/circular-buffer/README.md
rename to exercises/practice/circular-buffer/README.md
diff --git a/exercises/clock/.editorconfig b/exercises/practice/clock/.editorconfig
similarity index 100%
rename from exercises/clock/.editorconfig
rename to exercises/practice/clock/.editorconfig
diff --git a/exercises/clock/.meta/hints.md b/exercises/practice/clock/.meta/hints.md
similarity index 100%
rename from exercises/clock/.meta/hints.md
rename to exercises/practice/clock/.meta/hints.md
diff --git a/exercises/clock/.meta/tests.toml b/exercises/practice/clock/.meta/tests.toml
similarity index 100%
rename from exercises/clock/.meta/tests.toml
rename to exercises/practice/clock/.meta/tests.toml
diff --git a/exercises/clock/Clock.cs b/exercises/practice/clock/Clock.cs
similarity index 100%
rename from exercises/clock/Clock.cs
rename to exercises/practice/clock/Clock.cs
diff --git a/exercises/clock/Clock.csproj b/exercises/practice/clock/Clock.csproj
similarity index 100%
rename from exercises/clock/Clock.csproj
rename to exercises/practice/clock/Clock.csproj
diff --git a/exercises/clock/ClockTests.cs b/exercises/practice/clock/ClockTests.cs
similarity index 100%
rename from exercises/clock/ClockTests.cs
rename to exercises/practice/clock/ClockTests.cs
diff --git a/exercises/clock/Example.cs b/exercises/practice/clock/Example.cs
similarity index 100%
rename from exercises/clock/Example.cs
rename to exercises/practice/clock/Example.cs
diff --git a/exercises/clock/README.md b/exercises/practice/clock/README.md
similarity index 100%
rename from exercises/clock/README.md
rename to exercises/practice/clock/README.md
diff --git a/exercises/collatz-conjecture/.editorconfig b/exercises/practice/collatz-conjecture/.editorconfig
similarity index 100%
rename from exercises/collatz-conjecture/.editorconfig
rename to exercises/practice/collatz-conjecture/.editorconfig
diff --git a/exercises/collatz-conjecture/.meta/tests.toml b/exercises/practice/collatz-conjecture/.meta/tests.toml
similarity index 100%
rename from exercises/collatz-conjecture/.meta/tests.toml
rename to exercises/practice/collatz-conjecture/.meta/tests.toml
diff --git a/exercises/collatz-conjecture/CollatzConjecture.cs b/exercises/practice/collatz-conjecture/CollatzConjecture.cs
similarity index 100%
rename from exercises/collatz-conjecture/CollatzConjecture.cs
rename to exercises/practice/collatz-conjecture/CollatzConjecture.cs
diff --git a/exercises/collatz-conjecture/CollatzConjecture.csproj b/exercises/practice/collatz-conjecture/CollatzConjecture.csproj
similarity index 100%
rename from exercises/collatz-conjecture/CollatzConjecture.csproj
rename to exercises/practice/collatz-conjecture/CollatzConjecture.csproj
diff --git a/exercises/collatz-conjecture/CollatzConjectureTests.cs b/exercises/practice/collatz-conjecture/CollatzConjectureTests.cs
similarity index 100%
rename from exercises/collatz-conjecture/CollatzConjectureTests.cs
rename to exercises/practice/collatz-conjecture/CollatzConjectureTests.cs
diff --git a/exercises/collatz-conjecture/Example.cs b/exercises/practice/collatz-conjecture/Example.cs
similarity index 100%
rename from exercises/collatz-conjecture/Example.cs
rename to exercises/practice/collatz-conjecture/Example.cs
diff --git a/exercises/collatz-conjecture/README.md b/exercises/practice/collatz-conjecture/README.md
similarity index 100%
rename from exercises/collatz-conjecture/README.md
rename to exercises/practice/collatz-conjecture/README.md
diff --git a/exercises/complex-numbers/.editorconfig b/exercises/practice/complex-numbers/.editorconfig
similarity index 100%
rename from exercises/complex-numbers/.editorconfig
rename to exercises/practice/complex-numbers/.editorconfig
diff --git a/exercises/complex-numbers/.meta/tests.toml b/exercises/practice/complex-numbers/.meta/tests.toml
similarity index 100%
rename from exercises/complex-numbers/.meta/tests.toml
rename to exercises/practice/complex-numbers/.meta/tests.toml
diff --git a/exercises/complex-numbers/ComplexNumbers.cs b/exercises/practice/complex-numbers/ComplexNumbers.cs
similarity index 100%
rename from exercises/complex-numbers/ComplexNumbers.cs
rename to exercises/practice/complex-numbers/ComplexNumbers.cs
diff --git a/exercises/complex-numbers/ComplexNumbers.csproj b/exercises/practice/complex-numbers/ComplexNumbers.csproj
similarity index 100%
rename from exercises/complex-numbers/ComplexNumbers.csproj
rename to exercises/practice/complex-numbers/ComplexNumbers.csproj
diff --git a/exercises/complex-numbers/ComplexNumbersTests.cs b/exercises/practice/complex-numbers/ComplexNumbersTests.cs
similarity index 100%
rename from exercises/complex-numbers/ComplexNumbersTests.cs
rename to exercises/practice/complex-numbers/ComplexNumbersTests.cs
diff --git a/exercises/complex-numbers/Example.cs b/exercises/practice/complex-numbers/Example.cs
similarity index 100%
rename from exercises/complex-numbers/Example.cs
rename to exercises/practice/complex-numbers/Example.cs
diff --git a/exercises/complex-numbers/README.md b/exercises/practice/complex-numbers/README.md
similarity index 100%
rename from exercises/complex-numbers/README.md
rename to exercises/practice/complex-numbers/README.md
diff --git a/exercises/connect/.editorconfig b/exercises/practice/connect/.editorconfig
similarity index 100%
rename from exercises/connect/.editorconfig
rename to exercises/practice/connect/.editorconfig
diff --git a/exercises/connect/.meta/tests.toml b/exercises/practice/connect/.meta/tests.toml
similarity index 100%
rename from exercises/connect/.meta/tests.toml
rename to exercises/practice/connect/.meta/tests.toml
diff --git a/exercises/connect/Connect.cs b/exercises/practice/connect/Connect.cs
similarity index 100%
rename from exercises/connect/Connect.cs
rename to exercises/practice/connect/Connect.cs
diff --git a/exercises/connect/Connect.csproj b/exercises/practice/connect/Connect.csproj
similarity index 100%
rename from exercises/connect/Connect.csproj
rename to exercises/practice/connect/Connect.csproj
diff --git a/exercises/connect/ConnectTests.cs b/exercises/practice/connect/ConnectTests.cs
similarity index 100%
rename from exercises/connect/ConnectTests.cs
rename to exercises/practice/connect/ConnectTests.cs
diff --git a/exercises/connect/Example.cs b/exercises/practice/connect/Example.cs
similarity index 100%
rename from exercises/connect/Example.cs
rename to exercises/practice/connect/Example.cs
diff --git a/exercises/connect/README.md b/exercises/practice/connect/README.md
similarity index 100%
rename from exercises/connect/README.md
rename to exercises/practice/connect/README.md
diff --git a/exercises/crypto-square/.editorconfig b/exercises/practice/crypto-square/.editorconfig
similarity index 100%
rename from exercises/crypto-square/.editorconfig
rename to exercises/practice/crypto-square/.editorconfig
diff --git a/exercises/crypto-square/.meta/tests.toml b/exercises/practice/crypto-square/.meta/tests.toml
similarity index 100%
rename from exercises/crypto-square/.meta/tests.toml
rename to exercises/practice/crypto-square/.meta/tests.toml
diff --git a/exercises/crypto-square/CryptoSquare.cs b/exercises/practice/crypto-square/CryptoSquare.cs
similarity index 100%
rename from exercises/crypto-square/CryptoSquare.cs
rename to exercises/practice/crypto-square/CryptoSquare.cs
diff --git a/exercises/crypto-square/CryptoSquare.csproj b/exercises/practice/crypto-square/CryptoSquare.csproj
similarity index 100%
rename from exercises/crypto-square/CryptoSquare.csproj
rename to exercises/practice/crypto-square/CryptoSquare.csproj
diff --git a/exercises/crypto-square/CryptoSquareTests.cs b/exercises/practice/crypto-square/CryptoSquareTests.cs
similarity index 100%
rename from exercises/crypto-square/CryptoSquareTests.cs
rename to exercises/practice/crypto-square/CryptoSquareTests.cs
diff --git a/exercises/crypto-square/Example.cs b/exercises/practice/crypto-square/Example.cs
similarity index 100%
rename from exercises/crypto-square/Example.cs
rename to exercises/practice/crypto-square/Example.cs
diff --git a/exercises/crypto-square/README.md b/exercises/practice/crypto-square/README.md
similarity index 100%
rename from exercises/crypto-square/README.md
rename to exercises/practice/crypto-square/README.md
diff --git a/exercises/custom-set/.editorconfig b/exercises/practice/custom-set/.editorconfig
similarity index 100%
rename from exercises/custom-set/.editorconfig
rename to exercises/practice/custom-set/.editorconfig
diff --git a/exercises/custom-set/.meta/hints.md b/exercises/practice/custom-set/.meta/hints.md
similarity index 100%
rename from exercises/custom-set/.meta/hints.md
rename to exercises/practice/custom-set/.meta/hints.md
diff --git a/exercises/custom-set/.meta/tests.toml b/exercises/practice/custom-set/.meta/tests.toml
similarity index 100%
rename from exercises/custom-set/.meta/tests.toml
rename to exercises/practice/custom-set/.meta/tests.toml
diff --git a/exercises/custom-set/CustomSet.cs b/exercises/practice/custom-set/CustomSet.cs
similarity index 100%
rename from exercises/custom-set/CustomSet.cs
rename to exercises/practice/custom-set/CustomSet.cs
diff --git a/exercises/custom-set/CustomSet.csproj b/exercises/practice/custom-set/CustomSet.csproj
similarity index 100%
rename from exercises/custom-set/CustomSet.csproj
rename to exercises/practice/custom-set/CustomSet.csproj
diff --git a/exercises/custom-set/CustomSetTests.cs b/exercises/practice/custom-set/CustomSetTests.cs
similarity index 100%
rename from exercises/custom-set/CustomSetTests.cs
rename to exercises/practice/custom-set/CustomSetTests.cs
diff --git a/exercises/custom-set/Example.cs b/exercises/practice/custom-set/Example.cs
similarity index 100%
rename from exercises/custom-set/Example.cs
rename to exercises/practice/custom-set/Example.cs
diff --git a/exercises/custom-set/README.md b/exercises/practice/custom-set/README.md
similarity index 100%
rename from exercises/custom-set/README.md
rename to exercises/practice/custom-set/README.md
diff --git a/exercises/darts/.editorconfig b/exercises/practice/darts/.editorconfig
similarity index 100%
rename from exercises/darts/.editorconfig
rename to exercises/practice/darts/.editorconfig
diff --git a/exercises/darts/.meta/tests.toml b/exercises/practice/darts/.meta/tests.toml
similarity index 100%
rename from exercises/darts/.meta/tests.toml
rename to exercises/practice/darts/.meta/tests.toml
diff --git a/exercises/darts/Darts.cs b/exercises/practice/darts/Darts.cs
similarity index 100%
rename from exercises/darts/Darts.cs
rename to exercises/practice/darts/Darts.cs
diff --git a/exercises/darts/Darts.csproj b/exercises/practice/darts/Darts.csproj
similarity index 100%
rename from exercises/darts/Darts.csproj
rename to exercises/practice/darts/Darts.csproj
diff --git a/exercises/darts/DartsTests.cs b/exercises/practice/darts/DartsTests.cs
similarity index 100%
rename from exercises/darts/DartsTests.cs
rename to exercises/practice/darts/DartsTests.cs
diff --git a/exercises/darts/Example.cs b/exercises/practice/darts/Example.cs
similarity index 100%
rename from exercises/darts/Example.cs
rename to exercises/practice/darts/Example.cs
diff --git a/exercises/darts/README.md b/exercises/practice/darts/README.md
similarity index 100%
rename from exercises/darts/README.md
rename to exercises/practice/darts/README.md
diff --git a/exercises/diamond/.editorconfig b/exercises/practice/diamond/.editorconfig
similarity index 100%
rename from exercises/diamond/.editorconfig
rename to exercises/practice/diamond/.editorconfig
diff --git a/exercises/diamond/.meta/hints.md b/exercises/practice/diamond/.meta/hints.md
similarity index 100%
rename from exercises/diamond/.meta/hints.md
rename to exercises/practice/diamond/.meta/hints.md
diff --git a/exercises/diamond/.meta/tests.toml b/exercises/practice/diamond/.meta/tests.toml
similarity index 100%
rename from exercises/diamond/.meta/tests.toml
rename to exercises/practice/diamond/.meta/tests.toml
diff --git a/exercises/diamond/Diamond.cs b/exercises/practice/diamond/Diamond.cs
similarity index 100%
rename from exercises/diamond/Diamond.cs
rename to exercises/practice/diamond/Diamond.cs
diff --git a/exercises/diamond/Diamond.csproj b/exercises/practice/diamond/Diamond.csproj
similarity index 100%
rename from exercises/diamond/Diamond.csproj
rename to exercises/practice/diamond/Diamond.csproj
diff --git a/exercises/diamond/DiamondTests.cs b/exercises/practice/diamond/DiamondTests.cs
similarity index 100%
rename from exercises/diamond/DiamondTests.cs
rename to exercises/practice/diamond/DiamondTests.cs
diff --git a/exercises/diamond/Example.cs b/exercises/practice/diamond/Example.cs
similarity index 100%
rename from exercises/diamond/Example.cs
rename to exercises/practice/diamond/Example.cs
diff --git a/exercises/diamond/README.md b/exercises/practice/diamond/README.md
similarity index 100%
rename from exercises/diamond/README.md
rename to exercises/practice/diamond/README.md
diff --git a/exercises/difference-of-squares/.editorconfig b/exercises/practice/difference-of-squares/.editorconfig
similarity index 100%
rename from exercises/difference-of-squares/.editorconfig
rename to exercises/practice/difference-of-squares/.editorconfig
diff --git a/exercises/difference-of-squares/.meta/hints.md b/exercises/practice/difference-of-squares/.meta/hints.md
similarity index 100%
rename from exercises/difference-of-squares/.meta/hints.md
rename to exercises/practice/difference-of-squares/.meta/hints.md
diff --git a/exercises/difference-of-squares/.meta/tests.toml b/exercises/practice/difference-of-squares/.meta/tests.toml
similarity index 100%
rename from exercises/difference-of-squares/.meta/tests.toml
rename to exercises/practice/difference-of-squares/.meta/tests.toml
diff --git a/exercises/difference-of-squares/DifferenceOfSquares.cs b/exercises/practice/difference-of-squares/DifferenceOfSquares.cs
similarity index 100%
rename from exercises/difference-of-squares/DifferenceOfSquares.cs
rename to exercises/practice/difference-of-squares/DifferenceOfSquares.cs
diff --git a/exercises/difference-of-squares/DifferenceOfSquares.csproj b/exercises/practice/difference-of-squares/DifferenceOfSquares.csproj
similarity index 100%
rename from exercises/difference-of-squares/DifferenceOfSquares.csproj
rename to exercises/practice/difference-of-squares/DifferenceOfSquares.csproj
diff --git a/exercises/difference-of-squares/DifferenceOfSquaresTests.cs b/exercises/practice/difference-of-squares/DifferenceOfSquaresTests.cs
similarity index 100%
rename from exercises/difference-of-squares/DifferenceOfSquaresTests.cs
rename to exercises/practice/difference-of-squares/DifferenceOfSquaresTests.cs
diff --git a/exercises/difference-of-squares/Example.cs b/exercises/practice/difference-of-squares/Example.cs
similarity index 100%
rename from exercises/difference-of-squares/Example.cs
rename to exercises/practice/difference-of-squares/Example.cs
diff --git a/exercises/difference-of-squares/README.md b/exercises/practice/difference-of-squares/README.md
similarity index 100%
rename from exercises/difference-of-squares/README.md
rename to exercises/practice/difference-of-squares/README.md
diff --git a/exercises/diffie-hellman/.editorconfig b/exercises/practice/diffie-hellman/.editorconfig
similarity index 100%
rename from exercises/diffie-hellman/.editorconfig
rename to exercises/practice/diffie-hellman/.editorconfig
diff --git a/exercises/diffie-hellman/.meta/hints.md b/exercises/practice/diffie-hellman/.meta/hints.md
similarity index 100%
rename from exercises/diffie-hellman/.meta/hints.md
rename to exercises/practice/diffie-hellman/.meta/hints.md
diff --git a/exercises/diffie-hellman/.meta/tests.toml b/exercises/practice/diffie-hellman/.meta/tests.toml
similarity index 100%
rename from exercises/diffie-hellman/.meta/tests.toml
rename to exercises/practice/diffie-hellman/.meta/tests.toml
diff --git a/exercises/diffie-hellman/DiffieHellman.cs b/exercises/practice/diffie-hellman/DiffieHellman.cs
similarity index 100%
rename from exercises/diffie-hellman/DiffieHellman.cs
rename to exercises/practice/diffie-hellman/DiffieHellman.cs
diff --git a/exercises/diffie-hellman/DiffieHellman.csproj b/exercises/practice/diffie-hellman/DiffieHellman.csproj
similarity index 100%
rename from exercises/diffie-hellman/DiffieHellman.csproj
rename to exercises/practice/diffie-hellman/DiffieHellman.csproj
diff --git a/exercises/diffie-hellman/DiffieHellmanTests.cs b/exercises/practice/diffie-hellman/DiffieHellmanTests.cs
similarity index 100%
rename from exercises/diffie-hellman/DiffieHellmanTests.cs
rename to exercises/practice/diffie-hellman/DiffieHellmanTests.cs
diff --git a/exercises/diffie-hellman/Example.cs b/exercises/practice/diffie-hellman/Example.cs
similarity index 100%
rename from exercises/diffie-hellman/Example.cs
rename to exercises/practice/diffie-hellman/Example.cs
diff --git a/exercises/diffie-hellman/README.md b/exercises/practice/diffie-hellman/README.md
similarity index 100%
rename from exercises/diffie-hellman/README.md
rename to exercises/practice/diffie-hellman/README.md
diff --git a/exercises/dnd-character/.editorconfig b/exercises/practice/dnd-character/.editorconfig
similarity index 100%
rename from exercises/dnd-character/.editorconfig
rename to exercises/practice/dnd-character/.editorconfig
diff --git a/exercises/dnd-character/.meta/tests.toml b/exercises/practice/dnd-character/.meta/tests.toml
similarity index 100%
rename from exercises/dnd-character/.meta/tests.toml
rename to exercises/practice/dnd-character/.meta/tests.toml
diff --git a/exercises/dnd-character/DndCharacter.cs b/exercises/practice/dnd-character/DndCharacter.cs
similarity index 100%
rename from exercises/dnd-character/DndCharacter.cs
rename to exercises/practice/dnd-character/DndCharacter.cs
diff --git a/exercises/dnd-character/DndCharacter.csproj b/exercises/practice/dnd-character/DndCharacter.csproj
similarity index 100%
rename from exercises/dnd-character/DndCharacter.csproj
rename to exercises/practice/dnd-character/DndCharacter.csproj
diff --git a/exercises/dnd-character/DndCharacterTests.cs b/exercises/practice/dnd-character/DndCharacterTests.cs
similarity index 100%
rename from exercises/dnd-character/DndCharacterTests.cs
rename to exercises/practice/dnd-character/DndCharacterTests.cs
diff --git a/exercises/dnd-character/Example.cs b/exercises/practice/dnd-character/Example.cs
similarity index 100%
rename from exercises/dnd-character/Example.cs
rename to exercises/practice/dnd-character/Example.cs
diff --git a/exercises/dnd-character/README.md b/exercises/practice/dnd-character/README.md
similarity index 100%
rename from exercises/dnd-character/README.md
rename to exercises/practice/dnd-character/README.md
diff --git a/exercises/dominoes/.editorconfig b/exercises/practice/dominoes/.editorconfig
similarity index 100%
rename from exercises/dominoes/.editorconfig
rename to exercises/practice/dominoes/.editorconfig
diff --git a/exercises/dominoes/.meta/tests.toml b/exercises/practice/dominoes/.meta/tests.toml
similarity index 100%
rename from exercises/dominoes/.meta/tests.toml
rename to exercises/practice/dominoes/.meta/tests.toml
diff --git a/exercises/dominoes/Dominoes.cs b/exercises/practice/dominoes/Dominoes.cs
similarity index 100%
rename from exercises/dominoes/Dominoes.cs
rename to exercises/practice/dominoes/Dominoes.cs
diff --git a/exercises/dominoes/Dominoes.csproj b/exercises/practice/dominoes/Dominoes.csproj
similarity index 100%
rename from exercises/dominoes/Dominoes.csproj
rename to exercises/practice/dominoes/Dominoes.csproj
diff --git a/exercises/dominoes/DominoesTests.cs b/exercises/practice/dominoes/DominoesTests.cs
similarity index 100%
rename from exercises/dominoes/DominoesTests.cs
rename to exercises/practice/dominoes/DominoesTests.cs
diff --git a/exercises/dominoes/Example.cs b/exercises/practice/dominoes/Example.cs
similarity index 100%
rename from exercises/dominoes/Example.cs
rename to exercises/practice/dominoes/Example.cs
diff --git a/exercises/dominoes/README.md b/exercises/practice/dominoes/README.md
similarity index 100%
rename from exercises/dominoes/README.md
rename to exercises/practice/dominoes/README.md
diff --git a/exercises/dot-dsl/.editorconfig b/exercises/practice/dot-dsl/.editorconfig
similarity index 100%
rename from exercises/dot-dsl/.editorconfig
rename to exercises/practice/dot-dsl/.editorconfig
diff --git a/exercises/dot-dsl/.meta/hints.md b/exercises/practice/dot-dsl/.meta/hints.md
similarity index 100%
rename from exercises/dot-dsl/.meta/hints.md
rename to exercises/practice/dot-dsl/.meta/hints.md
diff --git a/exercises/dot-dsl/DotDsl.cs b/exercises/practice/dot-dsl/DotDsl.cs
similarity index 100%
rename from exercises/dot-dsl/DotDsl.cs
rename to exercises/practice/dot-dsl/DotDsl.cs
diff --git a/exercises/dot-dsl/DotDsl.csproj b/exercises/practice/dot-dsl/DotDsl.csproj
similarity index 100%
rename from exercises/dot-dsl/DotDsl.csproj
rename to exercises/practice/dot-dsl/DotDsl.csproj
diff --git a/exercises/dot-dsl/DotDslTests.cs b/exercises/practice/dot-dsl/DotDslTests.cs
similarity index 100%
rename from exercises/dot-dsl/DotDslTests.cs
rename to exercises/practice/dot-dsl/DotDslTests.cs
diff --git a/exercises/dot-dsl/Example.cs b/exercises/practice/dot-dsl/Example.cs
similarity index 100%
rename from exercises/dot-dsl/Example.cs
rename to exercises/practice/dot-dsl/Example.cs
diff --git a/exercises/dot-dsl/README.md b/exercises/practice/dot-dsl/README.md
similarity index 100%
rename from exercises/dot-dsl/README.md
rename to exercises/practice/dot-dsl/README.md
diff --git a/exercises/error-handling/.editorconfig b/exercises/practice/error-handling/.editorconfig
similarity index 100%
rename from exercises/error-handling/.editorconfig
rename to exercises/practice/error-handling/.editorconfig
diff --git a/exercises/error-handling/ErrorHandling.cs b/exercises/practice/error-handling/ErrorHandling.cs
similarity index 100%
rename from exercises/error-handling/ErrorHandling.cs
rename to exercises/practice/error-handling/ErrorHandling.cs
diff --git a/exercises/error-handling/ErrorHandling.csproj b/exercises/practice/error-handling/ErrorHandling.csproj
similarity index 100%
rename from exercises/error-handling/ErrorHandling.csproj
rename to exercises/practice/error-handling/ErrorHandling.csproj
diff --git a/exercises/error-handling/ErrorHandlingTests.cs b/exercises/practice/error-handling/ErrorHandlingTests.cs
similarity index 100%
rename from exercises/error-handling/ErrorHandlingTests.cs
rename to exercises/practice/error-handling/ErrorHandlingTests.cs
diff --git a/exercises/error-handling/Example.cs b/exercises/practice/error-handling/Example.cs
similarity index 100%
rename from exercises/error-handling/Example.cs
rename to exercises/practice/error-handling/Example.cs
diff --git a/exercises/error-handling/README.md b/exercises/practice/error-handling/README.md
similarity index 100%
rename from exercises/error-handling/README.md
rename to exercises/practice/error-handling/README.md
diff --git a/exercises/etl/.editorconfig b/exercises/practice/etl/.editorconfig
similarity index 100%
rename from exercises/etl/.editorconfig
rename to exercises/practice/etl/.editorconfig
diff --git a/exercises/etl/.meta/tests.toml b/exercises/practice/etl/.meta/tests.toml
similarity index 100%
rename from exercises/etl/.meta/tests.toml
rename to exercises/practice/etl/.meta/tests.toml
diff --git a/exercises/etl/Etl.cs b/exercises/practice/etl/Etl.cs
similarity index 100%
rename from exercises/etl/Etl.cs
rename to exercises/practice/etl/Etl.cs
diff --git a/exercises/etl/Etl.csproj b/exercises/practice/etl/Etl.csproj
similarity index 100%
rename from exercises/etl/Etl.csproj
rename to exercises/practice/etl/Etl.csproj
diff --git a/exercises/etl/EtlTests.cs b/exercises/practice/etl/EtlTests.cs
similarity index 100%
rename from exercises/etl/EtlTests.cs
rename to exercises/practice/etl/EtlTests.cs
diff --git a/exercises/etl/Example.cs b/exercises/practice/etl/Example.cs
similarity index 100%
rename from exercises/etl/Example.cs
rename to exercises/practice/etl/Example.cs
diff --git a/exercises/etl/README.md b/exercises/practice/etl/README.md
similarity index 100%
rename from exercises/etl/README.md
rename to exercises/practice/etl/README.md
diff --git a/exercises/flatten-array/.editorconfig b/exercises/practice/flatten-array/.editorconfig
similarity index 100%
rename from exercises/flatten-array/.editorconfig
rename to exercises/practice/flatten-array/.editorconfig
diff --git a/exercises/flatten-array/.meta/tests.toml b/exercises/practice/flatten-array/.meta/tests.toml
similarity index 100%
rename from exercises/flatten-array/.meta/tests.toml
rename to exercises/practice/flatten-array/.meta/tests.toml
diff --git a/exercises/flatten-array/Example.cs b/exercises/practice/flatten-array/Example.cs
similarity index 100%
rename from exercises/flatten-array/Example.cs
rename to exercises/practice/flatten-array/Example.cs
diff --git a/exercises/flatten-array/FlattenArray.cs b/exercises/practice/flatten-array/FlattenArray.cs
similarity index 100%
rename from exercises/flatten-array/FlattenArray.cs
rename to exercises/practice/flatten-array/FlattenArray.cs
diff --git a/exercises/flatten-array/FlattenArray.csproj b/exercises/practice/flatten-array/FlattenArray.csproj
similarity index 100%
rename from exercises/flatten-array/FlattenArray.csproj
rename to exercises/practice/flatten-array/FlattenArray.csproj
diff --git a/exercises/flatten-array/FlattenArrayTests.cs b/exercises/practice/flatten-array/FlattenArrayTests.cs
similarity index 100%
rename from exercises/flatten-array/FlattenArrayTests.cs
rename to exercises/practice/flatten-array/FlattenArrayTests.cs
diff --git a/exercises/flatten-array/README.md b/exercises/practice/flatten-array/README.md
similarity index 100%
rename from exercises/flatten-array/README.md
rename to exercises/practice/flatten-array/README.md
diff --git a/exercises/food-chain/.editorconfig b/exercises/practice/food-chain/.editorconfig
similarity index 100%
rename from exercises/food-chain/.editorconfig
rename to exercises/practice/food-chain/.editorconfig
diff --git a/exercises/food-chain/.meta/hints.md b/exercises/practice/food-chain/.meta/hints.md
similarity index 100%
rename from exercises/food-chain/.meta/hints.md
rename to exercises/practice/food-chain/.meta/hints.md
diff --git a/exercises/food-chain/.meta/tests.toml b/exercises/practice/food-chain/.meta/tests.toml
similarity index 100%
rename from exercises/food-chain/.meta/tests.toml
rename to exercises/practice/food-chain/.meta/tests.toml
diff --git a/exercises/food-chain/Example.cs b/exercises/practice/food-chain/Example.cs
similarity index 100%
rename from exercises/food-chain/Example.cs
rename to exercises/practice/food-chain/Example.cs
diff --git a/exercises/food-chain/FoodChain.cs b/exercises/practice/food-chain/FoodChain.cs
similarity index 100%
rename from exercises/food-chain/FoodChain.cs
rename to exercises/practice/food-chain/FoodChain.cs
diff --git a/exercises/food-chain/FoodChain.csproj b/exercises/practice/food-chain/FoodChain.csproj
similarity index 100%
rename from exercises/food-chain/FoodChain.csproj
rename to exercises/practice/food-chain/FoodChain.csproj
diff --git a/exercises/food-chain/FoodChainTests.cs b/exercises/practice/food-chain/FoodChainTests.cs
similarity index 100%
rename from exercises/food-chain/FoodChainTests.cs
rename to exercises/practice/food-chain/FoodChainTests.cs
diff --git a/exercises/food-chain/README.md b/exercises/practice/food-chain/README.md
similarity index 100%
rename from exercises/food-chain/README.md
rename to exercises/practice/food-chain/README.md
diff --git a/exercises/forth/.editorconfig b/exercises/practice/forth/.editorconfig
similarity index 100%
rename from exercises/forth/.editorconfig
rename to exercises/practice/forth/.editorconfig
diff --git a/exercises/forth/.meta/hints.md b/exercises/practice/forth/.meta/hints.md
similarity index 100%
rename from exercises/forth/.meta/hints.md
rename to exercises/practice/forth/.meta/hints.md
diff --git a/exercises/forth/.meta/tests.toml b/exercises/practice/forth/.meta/tests.toml
similarity index 100%
rename from exercises/forth/.meta/tests.toml
rename to exercises/practice/forth/.meta/tests.toml
diff --git a/exercises/forth/Example.cs b/exercises/practice/forth/Example.cs
similarity index 100%
rename from exercises/forth/Example.cs
rename to exercises/practice/forth/Example.cs
diff --git a/exercises/forth/Forth.cs b/exercises/practice/forth/Forth.cs
similarity index 100%
rename from exercises/forth/Forth.cs
rename to exercises/practice/forth/Forth.cs
diff --git a/exercises/forth/Forth.csproj b/exercises/practice/forth/Forth.csproj
similarity index 100%
rename from exercises/forth/Forth.csproj
rename to exercises/practice/forth/Forth.csproj
diff --git a/exercises/forth/ForthTests.cs b/exercises/practice/forth/ForthTests.cs
similarity index 100%
rename from exercises/forth/ForthTests.cs
rename to exercises/practice/forth/ForthTests.cs
diff --git a/exercises/forth/README.md b/exercises/practice/forth/README.md
similarity index 100%
rename from exercises/forth/README.md
rename to exercises/practice/forth/README.md
diff --git a/exercises/gigasecond/.editorconfig b/exercises/practice/gigasecond/.editorconfig
similarity index 100%
rename from exercises/gigasecond/.editorconfig
rename to exercises/practice/gigasecond/.editorconfig
diff --git a/exercises/gigasecond/.meta/tests.toml b/exercises/practice/gigasecond/.meta/tests.toml
similarity index 100%
rename from exercises/gigasecond/.meta/tests.toml
rename to exercises/practice/gigasecond/.meta/tests.toml
diff --git a/exercises/gigasecond/Example.cs b/exercises/practice/gigasecond/Example.cs
similarity index 100%
rename from exercises/gigasecond/Example.cs
rename to exercises/practice/gigasecond/Example.cs
diff --git a/exercises/gigasecond/Gigasecond.cs b/exercises/practice/gigasecond/Gigasecond.cs
similarity index 100%
rename from exercises/gigasecond/Gigasecond.cs
rename to exercises/practice/gigasecond/Gigasecond.cs
diff --git a/exercises/gigasecond/Gigasecond.csproj b/exercises/practice/gigasecond/Gigasecond.csproj
similarity index 100%
rename from exercises/gigasecond/Gigasecond.csproj
rename to exercises/practice/gigasecond/Gigasecond.csproj
diff --git a/exercises/gigasecond/GigasecondTests.cs b/exercises/practice/gigasecond/GigasecondTests.cs
similarity index 100%
rename from exercises/gigasecond/GigasecondTests.cs
rename to exercises/practice/gigasecond/GigasecondTests.cs
diff --git a/exercises/gigasecond/README.md b/exercises/practice/gigasecond/README.md
similarity index 100%
rename from exercises/gigasecond/README.md
rename to exercises/practice/gigasecond/README.md
diff --git a/exercises/go-counting/.editorconfig b/exercises/practice/go-counting/.editorconfig
similarity index 100%
rename from exercises/go-counting/.editorconfig
rename to exercises/practice/go-counting/.editorconfig
diff --git a/exercises/go-counting/.meta/tests.toml b/exercises/practice/go-counting/.meta/tests.toml
similarity index 100%
rename from exercises/go-counting/.meta/tests.toml
rename to exercises/practice/go-counting/.meta/tests.toml
diff --git a/exercises/go-counting/Example.cs b/exercises/practice/go-counting/Example.cs
similarity index 100%
rename from exercises/go-counting/Example.cs
rename to exercises/practice/go-counting/Example.cs
diff --git a/exercises/go-counting/GoCounting.cs b/exercises/practice/go-counting/GoCounting.cs
similarity index 100%
rename from exercises/go-counting/GoCounting.cs
rename to exercises/practice/go-counting/GoCounting.cs
diff --git a/exercises/go-counting/GoCounting.csproj b/exercises/practice/go-counting/GoCounting.csproj
similarity index 100%
rename from exercises/go-counting/GoCounting.csproj
rename to exercises/practice/go-counting/GoCounting.csproj
diff --git a/exercises/go-counting/GoCountingTests.cs b/exercises/practice/go-counting/GoCountingTests.cs
similarity index 100%
rename from exercises/go-counting/GoCountingTests.cs
rename to exercises/practice/go-counting/GoCountingTests.cs
diff --git a/exercises/go-counting/README.md b/exercises/practice/go-counting/README.md
similarity index 100%
rename from exercises/go-counting/README.md
rename to exercises/practice/go-counting/README.md
diff --git a/exercises/grade-school/.editorconfig b/exercises/practice/grade-school/.editorconfig
similarity index 100%
rename from exercises/grade-school/.editorconfig
rename to exercises/practice/grade-school/.editorconfig
diff --git a/exercises/grade-school/.meta/tests.toml b/exercises/practice/grade-school/.meta/tests.toml
similarity index 100%
rename from exercises/grade-school/.meta/tests.toml
rename to exercises/practice/grade-school/.meta/tests.toml
diff --git a/exercises/grade-school/Example.cs b/exercises/practice/grade-school/Example.cs
similarity index 100%
rename from exercises/grade-school/Example.cs
rename to exercises/practice/grade-school/Example.cs
diff --git a/exercises/grade-school/GradeSchool.cs b/exercises/practice/grade-school/GradeSchool.cs
similarity index 100%
rename from exercises/grade-school/GradeSchool.cs
rename to exercises/practice/grade-school/GradeSchool.cs
diff --git a/exercises/grade-school/GradeSchool.csproj b/exercises/practice/grade-school/GradeSchool.csproj
similarity index 100%
rename from exercises/grade-school/GradeSchool.csproj
rename to exercises/practice/grade-school/GradeSchool.csproj
diff --git a/exercises/grade-school/GradeSchoolTests.cs b/exercises/practice/grade-school/GradeSchoolTests.cs
similarity index 100%
rename from exercises/grade-school/GradeSchoolTests.cs
rename to exercises/practice/grade-school/GradeSchoolTests.cs
diff --git a/exercises/grade-school/README.md b/exercises/practice/grade-school/README.md
similarity index 100%
rename from exercises/grade-school/README.md
rename to exercises/practice/grade-school/README.md
diff --git a/exercises/grains/.editorconfig b/exercises/practice/grains/.editorconfig
similarity index 100%
rename from exercises/grains/.editorconfig
rename to exercises/practice/grains/.editorconfig
diff --git a/exercises/grains/.meta/tests.toml b/exercises/practice/grains/.meta/tests.toml
similarity index 100%
rename from exercises/grains/.meta/tests.toml
rename to exercises/practice/grains/.meta/tests.toml
diff --git a/exercises/grains/Example.cs b/exercises/practice/grains/Example.cs
similarity index 100%
rename from exercises/grains/Example.cs
rename to exercises/practice/grains/Example.cs
diff --git a/exercises/grains/Grains.cs b/exercises/practice/grains/Grains.cs
similarity index 100%
rename from exercises/grains/Grains.cs
rename to exercises/practice/grains/Grains.cs
diff --git a/exercises/grains/Grains.csproj b/exercises/practice/grains/Grains.csproj
similarity index 100%
rename from exercises/grains/Grains.csproj
rename to exercises/practice/grains/Grains.csproj
diff --git a/exercises/grains/GrainsTests.cs b/exercises/practice/grains/GrainsTests.cs
similarity index 100%
rename from exercises/grains/GrainsTests.cs
rename to exercises/practice/grains/GrainsTests.cs
diff --git a/exercises/grains/README.md b/exercises/practice/grains/README.md
similarity index 100%
rename from exercises/grains/README.md
rename to exercises/practice/grains/README.md
diff --git a/exercises/grep/.editorconfig b/exercises/practice/grep/.editorconfig
similarity index 100%
rename from exercises/grep/.editorconfig
rename to exercises/practice/grep/.editorconfig
diff --git a/exercises/grep/.meta/tests.toml b/exercises/practice/grep/.meta/tests.toml
similarity index 100%
rename from exercises/grep/.meta/tests.toml
rename to exercises/practice/grep/.meta/tests.toml
diff --git a/exercises/grep/Example.cs b/exercises/practice/grep/Example.cs
similarity index 100%
rename from exercises/grep/Example.cs
rename to exercises/practice/grep/Example.cs
diff --git a/exercises/grep/Grep.cs b/exercises/practice/grep/Grep.cs
similarity index 100%
rename from exercises/grep/Grep.cs
rename to exercises/practice/grep/Grep.cs
diff --git a/exercises/grep/Grep.csproj b/exercises/practice/grep/Grep.csproj
similarity index 100%
rename from exercises/grep/Grep.csproj
rename to exercises/practice/grep/Grep.csproj
diff --git a/exercises/grep/GrepTests.cs b/exercises/practice/grep/GrepTests.cs
similarity index 100%
rename from exercises/grep/GrepTests.cs
rename to exercises/practice/grep/GrepTests.cs
diff --git a/exercises/grep/README.md b/exercises/practice/grep/README.md
similarity index 100%
rename from exercises/grep/README.md
rename to exercises/practice/grep/README.md
diff --git a/exercises/hamming/.editorconfig b/exercises/practice/hamming/.editorconfig
similarity index 100%
rename from exercises/hamming/.editorconfig
rename to exercises/practice/hamming/.editorconfig
diff --git a/exercises/hamming/.meta/tests.toml b/exercises/practice/hamming/.meta/tests.toml
similarity index 100%
rename from exercises/hamming/.meta/tests.toml
rename to exercises/practice/hamming/.meta/tests.toml
diff --git a/exercises/hamming/Example.cs b/exercises/practice/hamming/Example.cs
similarity index 100%
rename from exercises/hamming/Example.cs
rename to exercises/practice/hamming/Example.cs
diff --git a/exercises/hamming/Hamming.cs b/exercises/practice/hamming/Hamming.cs
similarity index 100%
rename from exercises/hamming/Hamming.cs
rename to exercises/practice/hamming/Hamming.cs
diff --git a/exercises/hamming/Hamming.csproj b/exercises/practice/hamming/Hamming.csproj
similarity index 100%
rename from exercises/hamming/Hamming.csproj
rename to exercises/practice/hamming/Hamming.csproj
diff --git a/exercises/hamming/HammingTests.cs b/exercises/practice/hamming/HammingTests.cs
similarity index 100%
rename from exercises/hamming/HammingTests.cs
rename to exercises/practice/hamming/HammingTests.cs
diff --git a/exercises/hamming/README.md b/exercises/practice/hamming/README.md
similarity index 100%
rename from exercises/hamming/README.md
rename to exercises/practice/hamming/README.md
diff --git a/exercises/hangman/.editorconfig b/exercises/practice/hangman/.editorconfig
similarity index 100%
rename from exercises/hangman/.editorconfig
rename to exercises/practice/hangman/.editorconfig
diff --git a/exercises/hangman/.meta/hints.md b/exercises/practice/hangman/.meta/hints.md
similarity index 100%
rename from exercises/hangman/.meta/hints.md
rename to exercises/practice/hangman/.meta/hints.md
diff --git a/exercises/hangman/Example.cs b/exercises/practice/hangman/Example.cs
similarity index 100%
rename from exercises/hangman/Example.cs
rename to exercises/practice/hangman/Example.cs
diff --git a/exercises/hangman/Hangman.cs b/exercises/practice/hangman/Hangman.cs
similarity index 100%
rename from exercises/hangman/Hangman.cs
rename to exercises/practice/hangman/Hangman.cs
diff --git a/exercises/hangman/Hangman.csproj b/exercises/practice/hangman/Hangman.csproj
similarity index 100%
rename from exercises/hangman/Hangman.csproj
rename to exercises/practice/hangman/Hangman.csproj
diff --git a/exercises/hangman/HangmanTests.cs b/exercises/practice/hangman/HangmanTests.cs
similarity index 100%
rename from exercises/hangman/HangmanTests.cs
rename to exercises/practice/hangman/HangmanTests.cs
diff --git a/exercises/hangman/README.md b/exercises/practice/hangman/README.md
similarity index 100%
rename from exercises/hangman/README.md
rename to exercises/practice/hangman/README.md
diff --git a/exercises/hello-world/.editorconfig b/exercises/practice/hello-world/.editorconfig
similarity index 100%
rename from exercises/hello-world/.editorconfig
rename to exercises/practice/hello-world/.editorconfig
diff --git a/exercises/hello-world/.meta/tests.toml b/exercises/practice/hello-world/.meta/tests.toml
similarity index 100%
rename from exercises/hello-world/.meta/tests.toml
rename to exercises/practice/hello-world/.meta/tests.toml
diff --git a/exercises/hello-world/Example.cs b/exercises/practice/hello-world/Example.cs
similarity index 100%
rename from exercises/hello-world/Example.cs
rename to exercises/practice/hello-world/Example.cs
diff --git a/exercises/hello-world/HelloWorld.cs b/exercises/practice/hello-world/HelloWorld.cs
similarity index 100%
rename from exercises/hello-world/HelloWorld.cs
rename to exercises/practice/hello-world/HelloWorld.cs
diff --git a/exercises/hello-world/HelloWorld.csproj b/exercises/practice/hello-world/HelloWorld.csproj
similarity index 100%
rename from exercises/hello-world/HelloWorld.csproj
rename to exercises/practice/hello-world/HelloWorld.csproj
diff --git a/exercises/hello-world/HelloWorldTests.cs b/exercises/practice/hello-world/HelloWorldTests.cs
similarity index 100%
rename from exercises/hello-world/HelloWorldTests.cs
rename to exercises/practice/hello-world/HelloWorldTests.cs
diff --git a/exercises/hello-world/README.md b/exercises/practice/hello-world/README.md
similarity index 100%
rename from exercises/hello-world/README.md
rename to exercises/practice/hello-world/README.md
diff --git a/exercises/hexadecimal/.editorconfig b/exercises/practice/hexadecimal/.editorconfig
similarity index 100%
rename from exercises/hexadecimal/.editorconfig
rename to exercises/practice/hexadecimal/.editorconfig
diff --git a/exercises/hexadecimal/Example.cs b/exercises/practice/hexadecimal/Example.cs
similarity index 100%
rename from exercises/hexadecimal/Example.cs
rename to exercises/practice/hexadecimal/Example.cs
diff --git a/exercises/hexadecimal/Hexadecimal.cs b/exercises/practice/hexadecimal/Hexadecimal.cs
similarity index 100%
rename from exercises/hexadecimal/Hexadecimal.cs
rename to exercises/practice/hexadecimal/Hexadecimal.cs
diff --git a/exercises/hexadecimal/Hexadecimal.csproj b/exercises/practice/hexadecimal/Hexadecimal.csproj
similarity index 100%
rename from exercises/hexadecimal/Hexadecimal.csproj
rename to exercises/practice/hexadecimal/Hexadecimal.csproj
diff --git a/exercises/hexadecimal/HexadecimalTests.cs b/exercises/practice/hexadecimal/HexadecimalTests.cs
similarity index 100%
rename from exercises/hexadecimal/HexadecimalTests.cs
rename to exercises/practice/hexadecimal/HexadecimalTests.cs
diff --git a/exercises/hexadecimal/README.md b/exercises/practice/hexadecimal/README.md
similarity index 100%
rename from exercises/hexadecimal/README.md
rename to exercises/practice/hexadecimal/README.md
diff --git a/exercises/high-scores/.editorconfig b/exercises/practice/high-scores/.editorconfig
similarity index 100%
rename from exercises/high-scores/.editorconfig
rename to exercises/practice/high-scores/.editorconfig
diff --git a/exercises/high-scores/.meta/tests.toml b/exercises/practice/high-scores/.meta/tests.toml
similarity index 100%
rename from exercises/high-scores/.meta/tests.toml
rename to exercises/practice/high-scores/.meta/tests.toml
diff --git a/exercises/high-scores/Example.cs b/exercises/practice/high-scores/Example.cs
similarity index 100%
rename from exercises/high-scores/Example.cs
rename to exercises/practice/high-scores/Example.cs
diff --git a/exercises/high-scores/HighScores.cs b/exercises/practice/high-scores/HighScores.cs
similarity index 100%
rename from exercises/high-scores/HighScores.cs
rename to exercises/practice/high-scores/HighScores.cs
diff --git a/exercises/high-scores/HighScores.csproj b/exercises/practice/high-scores/HighScores.csproj
similarity index 100%
rename from exercises/high-scores/HighScores.csproj
rename to exercises/practice/high-scores/HighScores.csproj
diff --git a/exercises/high-scores/HighScoresTests.cs b/exercises/practice/high-scores/HighScoresTests.cs
similarity index 100%
rename from exercises/high-scores/HighScoresTests.cs
rename to exercises/practice/high-scores/HighScoresTests.cs
diff --git a/exercises/high-scores/README.md b/exercises/practice/high-scores/README.md
similarity index 100%
rename from exercises/high-scores/README.md
rename to exercises/practice/high-scores/README.md
diff --git a/exercises/house/.editorconfig b/exercises/practice/house/.editorconfig
similarity index 100%
rename from exercises/house/.editorconfig
rename to exercises/practice/house/.editorconfig
diff --git a/exercises/house/.meta/hints.md b/exercises/practice/house/.meta/hints.md
similarity index 100%
rename from exercises/house/.meta/hints.md
rename to exercises/practice/house/.meta/hints.md
diff --git a/exercises/house/.meta/tests.toml b/exercises/practice/house/.meta/tests.toml
similarity index 100%
rename from exercises/house/.meta/tests.toml
rename to exercises/practice/house/.meta/tests.toml
diff --git a/exercises/house/Example.cs b/exercises/practice/house/Example.cs
similarity index 100%
rename from exercises/house/Example.cs
rename to exercises/practice/house/Example.cs
diff --git a/exercises/house/House.cs b/exercises/practice/house/House.cs
similarity index 100%
rename from exercises/house/House.cs
rename to exercises/practice/house/House.cs
diff --git a/exercises/house/House.csproj b/exercises/practice/house/House.csproj
similarity index 100%
rename from exercises/house/House.csproj
rename to exercises/practice/house/House.csproj
diff --git a/exercises/house/HouseTests.cs b/exercises/practice/house/HouseTests.cs
similarity index 100%
rename from exercises/house/HouseTests.cs
rename to exercises/practice/house/HouseTests.cs
diff --git a/exercises/house/README.md b/exercises/practice/house/README.md
similarity index 100%
rename from exercises/house/README.md
rename to exercises/practice/house/README.md
diff --git a/exercises/isbn-verifier/.editorconfig b/exercises/practice/isbn-verifier/.editorconfig
similarity index 100%
rename from exercises/isbn-verifier/.editorconfig
rename to exercises/practice/isbn-verifier/.editorconfig
diff --git a/exercises/isbn-verifier/.meta/tests.toml b/exercises/practice/isbn-verifier/.meta/tests.toml
similarity index 100%
rename from exercises/isbn-verifier/.meta/tests.toml
rename to exercises/practice/isbn-verifier/.meta/tests.toml
diff --git a/exercises/isbn-verifier/Example.cs b/exercises/practice/isbn-verifier/Example.cs
similarity index 100%
rename from exercises/isbn-verifier/Example.cs
rename to exercises/practice/isbn-verifier/Example.cs
diff --git a/exercises/isbn-verifier/IsbnVerifier.cs b/exercises/practice/isbn-verifier/IsbnVerifier.cs
similarity index 100%
rename from exercises/isbn-verifier/IsbnVerifier.cs
rename to exercises/practice/isbn-verifier/IsbnVerifier.cs
diff --git a/exercises/isbn-verifier/IsbnVerifier.csproj b/exercises/practice/isbn-verifier/IsbnVerifier.csproj
similarity index 100%
rename from exercises/isbn-verifier/IsbnVerifier.csproj
rename to exercises/practice/isbn-verifier/IsbnVerifier.csproj
diff --git a/exercises/isbn-verifier/IsbnVerifierTests.cs b/exercises/practice/isbn-verifier/IsbnVerifierTests.cs
similarity index 100%
rename from exercises/isbn-verifier/IsbnVerifierTests.cs
rename to exercises/practice/isbn-verifier/IsbnVerifierTests.cs
diff --git a/exercises/isbn-verifier/README.md b/exercises/practice/isbn-verifier/README.md
similarity index 100%
rename from exercises/isbn-verifier/README.md
rename to exercises/practice/isbn-verifier/README.md
diff --git a/exercises/isogram/.editorconfig b/exercises/practice/isogram/.editorconfig
similarity index 100%
rename from exercises/isogram/.editorconfig
rename to exercises/practice/isogram/.editorconfig
diff --git a/exercises/isogram/.meta/tests.toml b/exercises/practice/isogram/.meta/tests.toml
similarity index 100%
rename from exercises/isogram/.meta/tests.toml
rename to exercises/practice/isogram/.meta/tests.toml
diff --git a/exercises/isogram/Example.cs b/exercises/practice/isogram/Example.cs
similarity index 100%
rename from exercises/isogram/Example.cs
rename to exercises/practice/isogram/Example.cs
diff --git a/exercises/isogram/Isogram.cs b/exercises/practice/isogram/Isogram.cs
similarity index 100%
rename from exercises/isogram/Isogram.cs
rename to exercises/practice/isogram/Isogram.cs
diff --git a/exercises/isogram/Isogram.csproj b/exercises/practice/isogram/Isogram.csproj
similarity index 100%
rename from exercises/isogram/Isogram.csproj
rename to exercises/practice/isogram/Isogram.csproj
diff --git a/exercises/isogram/IsogramTests.cs b/exercises/practice/isogram/IsogramTests.cs
similarity index 100%
rename from exercises/isogram/IsogramTests.cs
rename to exercises/practice/isogram/IsogramTests.cs
diff --git a/exercises/isogram/README.md b/exercises/practice/isogram/README.md
similarity index 100%
rename from exercises/isogram/README.md
rename to exercises/practice/isogram/README.md
diff --git a/exercises/kindergarten-garden/.editorconfig b/exercises/practice/kindergarten-garden/.editorconfig
similarity index 100%
rename from exercises/kindergarten-garden/.editorconfig
rename to exercises/practice/kindergarten-garden/.editorconfig
diff --git a/exercises/kindergarten-garden/.meta/tests.toml b/exercises/practice/kindergarten-garden/.meta/tests.toml
similarity index 100%
rename from exercises/kindergarten-garden/.meta/tests.toml
rename to exercises/practice/kindergarten-garden/.meta/tests.toml
diff --git a/exercises/kindergarten-garden/Example.cs b/exercises/practice/kindergarten-garden/Example.cs
similarity index 100%
rename from exercises/kindergarten-garden/Example.cs
rename to exercises/practice/kindergarten-garden/Example.cs
diff --git a/exercises/kindergarten-garden/KindergartenGarden.cs b/exercises/practice/kindergarten-garden/KindergartenGarden.cs
similarity index 100%
rename from exercises/kindergarten-garden/KindergartenGarden.cs
rename to exercises/practice/kindergarten-garden/KindergartenGarden.cs
diff --git a/exercises/kindergarten-garden/KindergartenGarden.csproj b/exercises/practice/kindergarten-garden/KindergartenGarden.csproj
similarity index 100%
rename from exercises/kindergarten-garden/KindergartenGarden.csproj
rename to exercises/practice/kindergarten-garden/KindergartenGarden.csproj
diff --git a/exercises/kindergarten-garden/KindergartenGardenTests.cs b/exercises/practice/kindergarten-garden/KindergartenGardenTests.cs
similarity index 100%
rename from exercises/kindergarten-garden/KindergartenGardenTests.cs
rename to exercises/practice/kindergarten-garden/KindergartenGardenTests.cs
diff --git a/exercises/kindergarten-garden/README.md b/exercises/practice/kindergarten-garden/README.md
similarity index 100%
rename from exercises/kindergarten-garden/README.md
rename to exercises/practice/kindergarten-garden/README.md
diff --git a/exercises/largest-series-product/.editorconfig b/exercises/practice/largest-series-product/.editorconfig
similarity index 100%
rename from exercises/largest-series-product/.editorconfig
rename to exercises/practice/largest-series-product/.editorconfig
diff --git a/exercises/largest-series-product/.meta/tests.toml b/exercises/practice/largest-series-product/.meta/tests.toml
similarity index 100%
rename from exercises/largest-series-product/.meta/tests.toml
rename to exercises/practice/largest-series-product/.meta/tests.toml
diff --git a/exercises/largest-series-product/Example.cs b/exercises/practice/largest-series-product/Example.cs
similarity index 97%
rename from exercises/largest-series-product/Example.cs
rename to exercises/practice/largest-series-product/Example.cs
index c95e399e33..0b45a0c33a 100644
--- a/exercises/largest-series-product/Example.cs
+++ b/exercises/practice/largest-series-product/Example.cs
@@ -1,34 +1,34 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-public static class LargestSeriesProduct
-{
-    public static long GetLargestProduct(string digits, int span) => GetSlices(ParseDigits(digits), span).Max(l => GetProduct(l));
-
-    private static IEnumerable> GetSlices(long[] digits, int span)
-    {
-        if (span < 0 || span > digits.Length)
-        {
-            throw new ArgumentException("Invalid span.");
-        }
-
-        return Enumerable.Range(0, GetNumberOfSlices(digits, span)).Select(i => digits.Skip(i).Take(span));
-    }
-
-    private static long[] ParseDigits(string digits) => digits.ToCharArray().Select(ParseDigit).ToArray();
-
-    private static long ParseDigit(char c)
-    {
-        if (!char.IsDigit(c))
-        {
-            throw new ArgumentException("Invalid digit.");
-        }
-
-        return long.Parse(c.ToString());
-    }
-
-    private static long GetProduct(IEnumerable numbers) => numbers.Aggregate(1L, (x, product) => x * product);
-
-    private static int GetNumberOfSlices(long[] digits, int span) => digits.Length + 1 - span;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+public static class LargestSeriesProduct
+{
+    public static long GetLargestProduct(string digits, int span) => GetSlices(ParseDigits(digits), span).Max(l => GetProduct(l));
+
+    private static IEnumerable> GetSlices(long[] digits, int span)
+    {
+        if (span < 0 || span > digits.Length)
+        {
+            throw new ArgumentException("Invalid span.");
+        }
+
+        return Enumerable.Range(0, GetNumberOfSlices(digits, span)).Select(i => digits.Skip(i).Take(span));
+    }
+
+    private static long[] ParseDigits(string digits) => digits.ToCharArray().Select(ParseDigit).ToArray();
+
+    private static long ParseDigit(char c)
+    {
+        if (!char.IsDigit(c))
+        {
+            throw new ArgumentException("Invalid digit.");
+        }
+
+        return long.Parse(c.ToString());
+    }
+
+    private static long GetProduct(IEnumerable numbers) => numbers.Aggregate(1L, (x, product) => x * product);
+
+    private static int GetNumberOfSlices(long[] digits, int span) => digits.Length + 1 - span;
 }
\ No newline at end of file
diff --git a/exercises/largest-series-product/LargestSeriesProduct.cs b/exercises/practice/largest-series-product/LargestSeriesProduct.cs
similarity index 100%
rename from exercises/largest-series-product/LargestSeriesProduct.cs
rename to exercises/practice/largest-series-product/LargestSeriesProduct.cs
diff --git a/exercises/largest-series-product/LargestSeriesProduct.csproj b/exercises/practice/largest-series-product/LargestSeriesProduct.csproj
similarity index 100%
rename from exercises/largest-series-product/LargestSeriesProduct.csproj
rename to exercises/practice/largest-series-product/LargestSeriesProduct.csproj
diff --git a/exercises/largest-series-product/LargestSeriesProductTests.cs b/exercises/practice/largest-series-product/LargestSeriesProductTests.cs
similarity index 100%
rename from exercises/largest-series-product/LargestSeriesProductTests.cs
rename to exercises/practice/largest-series-product/LargestSeriesProductTests.cs
diff --git a/exercises/largest-series-product/README.md b/exercises/practice/largest-series-product/README.md
similarity index 100%
rename from exercises/largest-series-product/README.md
rename to exercises/practice/largest-series-product/README.md
diff --git a/exercises/leap/.editorconfig b/exercises/practice/leap/.editorconfig
similarity index 100%
rename from exercises/leap/.editorconfig
rename to exercises/practice/leap/.editorconfig
diff --git a/exercises/leap/.meta/hints.md b/exercises/practice/leap/.meta/hints.md
similarity index 100%
rename from exercises/leap/.meta/hints.md
rename to exercises/practice/leap/.meta/hints.md
diff --git a/exercises/leap/.meta/tests.toml b/exercises/practice/leap/.meta/tests.toml
similarity index 100%
rename from exercises/leap/.meta/tests.toml
rename to exercises/practice/leap/.meta/tests.toml
diff --git a/exercises/leap/Example.cs b/exercises/practice/leap/Example.cs
similarity index 100%
rename from exercises/leap/Example.cs
rename to exercises/practice/leap/Example.cs
diff --git a/exercises/leap/Leap.cs b/exercises/practice/leap/Leap.cs
similarity index 100%
rename from exercises/leap/Leap.cs
rename to exercises/practice/leap/Leap.cs
diff --git a/exercises/leap/Leap.csproj b/exercises/practice/leap/Leap.csproj
similarity index 100%
rename from exercises/leap/Leap.csproj
rename to exercises/practice/leap/Leap.csproj
diff --git a/exercises/leap/LeapTests.cs b/exercises/practice/leap/LeapTests.cs
similarity index 100%
rename from exercises/leap/LeapTests.cs
rename to exercises/practice/leap/LeapTests.cs
diff --git a/exercises/leap/README.md b/exercises/practice/leap/README.md
similarity index 100%
rename from exercises/leap/README.md
rename to exercises/practice/leap/README.md
diff --git a/exercises/ledger/.editorconfig b/exercises/practice/ledger/.editorconfig
similarity index 100%
rename from exercises/ledger/.editorconfig
rename to exercises/practice/ledger/.editorconfig
diff --git a/exercises/ledger/Example.cs b/exercises/practice/ledger/Example.cs
similarity index 100%
rename from exercises/ledger/Example.cs
rename to exercises/practice/ledger/Example.cs
diff --git a/exercises/ledger/Ledger.cs b/exercises/practice/ledger/Ledger.cs
similarity index 100%
rename from exercises/ledger/Ledger.cs
rename to exercises/practice/ledger/Ledger.cs
diff --git a/exercises/ledger/Ledger.csproj b/exercises/practice/ledger/Ledger.csproj
similarity index 100%
rename from exercises/ledger/Ledger.csproj
rename to exercises/practice/ledger/Ledger.csproj
diff --git a/exercises/ledger/LedgerTests.cs b/exercises/practice/ledger/LedgerTests.cs
similarity index 100%
rename from exercises/ledger/LedgerTests.cs
rename to exercises/practice/ledger/LedgerTests.cs
diff --git a/exercises/ledger/README.md b/exercises/practice/ledger/README.md
similarity index 100%
rename from exercises/ledger/README.md
rename to exercises/practice/ledger/README.md
diff --git a/exercises/linked-list/.editorconfig b/exercises/practice/linked-list/.editorconfig
similarity index 100%
rename from exercises/linked-list/.editorconfig
rename to exercises/practice/linked-list/.editorconfig
diff --git a/exercises/linked-list/Example.cs b/exercises/practice/linked-list/Example.cs
similarity index 100%
rename from exercises/linked-list/Example.cs
rename to exercises/practice/linked-list/Example.cs
diff --git a/exercises/linked-list/LinkedList.cs b/exercises/practice/linked-list/LinkedList.cs
similarity index 100%
rename from exercises/linked-list/LinkedList.cs
rename to exercises/practice/linked-list/LinkedList.cs
diff --git a/exercises/linked-list/LinkedList.csproj b/exercises/practice/linked-list/LinkedList.csproj
similarity index 100%
rename from exercises/linked-list/LinkedList.csproj
rename to exercises/practice/linked-list/LinkedList.csproj
diff --git a/exercises/linked-list/LinkedListTests.cs b/exercises/practice/linked-list/LinkedListTests.cs
similarity index 100%
rename from exercises/linked-list/LinkedListTests.cs
rename to exercises/practice/linked-list/LinkedListTests.cs
diff --git a/exercises/linked-list/README.md b/exercises/practice/linked-list/README.md
similarity index 100%
rename from exercises/linked-list/README.md
rename to exercises/practice/linked-list/README.md
diff --git a/exercises/list-ops/.editorconfig b/exercises/practice/list-ops/.editorconfig
similarity index 100%
rename from exercises/list-ops/.editorconfig
rename to exercises/practice/list-ops/.editorconfig
diff --git a/exercises/list-ops/.meta/hints.md b/exercises/practice/list-ops/.meta/hints.md
similarity index 100%
rename from exercises/list-ops/.meta/hints.md
rename to exercises/practice/list-ops/.meta/hints.md
diff --git a/exercises/list-ops/.meta/tests.toml b/exercises/practice/list-ops/.meta/tests.toml
similarity index 100%
rename from exercises/list-ops/.meta/tests.toml
rename to exercises/practice/list-ops/.meta/tests.toml
diff --git a/exercises/list-ops/Example.cs b/exercises/practice/list-ops/Example.cs
similarity index 100%
rename from exercises/list-ops/Example.cs
rename to exercises/practice/list-ops/Example.cs
diff --git a/exercises/list-ops/ListOps.cs b/exercises/practice/list-ops/ListOps.cs
similarity index 100%
rename from exercises/list-ops/ListOps.cs
rename to exercises/practice/list-ops/ListOps.cs
diff --git a/exercises/list-ops/ListOps.csproj b/exercises/practice/list-ops/ListOps.csproj
similarity index 100%
rename from exercises/list-ops/ListOps.csproj
rename to exercises/practice/list-ops/ListOps.csproj
diff --git a/exercises/list-ops/ListOpsTests.cs b/exercises/practice/list-ops/ListOpsTests.cs
similarity index 100%
rename from exercises/list-ops/ListOpsTests.cs
rename to exercises/practice/list-ops/ListOpsTests.cs
diff --git a/exercises/list-ops/README.md b/exercises/practice/list-ops/README.md
similarity index 100%
rename from exercises/list-ops/README.md
rename to exercises/practice/list-ops/README.md
diff --git a/exercises/luhn/.editorconfig b/exercises/practice/luhn/.editorconfig
similarity index 100%
rename from exercises/luhn/.editorconfig
rename to exercises/practice/luhn/.editorconfig
diff --git a/exercises/luhn/.meta/tests.toml b/exercises/practice/luhn/.meta/tests.toml
similarity index 100%
rename from exercises/luhn/.meta/tests.toml
rename to exercises/practice/luhn/.meta/tests.toml
diff --git a/exercises/luhn/Example.cs b/exercises/practice/luhn/Example.cs
similarity index 100%
rename from exercises/luhn/Example.cs
rename to exercises/practice/luhn/Example.cs
diff --git a/exercises/luhn/Luhn.cs b/exercises/practice/luhn/Luhn.cs
similarity index 100%
rename from exercises/luhn/Luhn.cs
rename to exercises/practice/luhn/Luhn.cs
diff --git a/exercises/luhn/Luhn.csproj b/exercises/practice/luhn/Luhn.csproj
similarity index 100%
rename from exercises/luhn/Luhn.csproj
rename to exercises/practice/luhn/Luhn.csproj
diff --git a/exercises/luhn/LuhnTests.cs b/exercises/practice/luhn/LuhnTests.cs
similarity index 100%
rename from exercises/luhn/LuhnTests.cs
rename to exercises/practice/luhn/LuhnTests.cs
diff --git a/exercises/luhn/README.md b/exercises/practice/luhn/README.md
similarity index 100%
rename from exercises/luhn/README.md
rename to exercises/practice/luhn/README.md
diff --git a/exercises/markdown/.editorconfig b/exercises/practice/markdown/.editorconfig
similarity index 100%
rename from exercises/markdown/.editorconfig
rename to exercises/practice/markdown/.editorconfig
diff --git a/exercises/markdown/.meta/hints.md b/exercises/practice/markdown/.meta/hints.md
similarity index 100%
rename from exercises/markdown/.meta/hints.md
rename to exercises/practice/markdown/.meta/hints.md
diff --git a/exercises/markdown/.meta/tests.toml b/exercises/practice/markdown/.meta/tests.toml
similarity index 100%
rename from exercises/markdown/.meta/tests.toml
rename to exercises/practice/markdown/.meta/tests.toml
diff --git a/exercises/markdown/Example.cs b/exercises/practice/markdown/Example.cs
similarity index 100%
rename from exercises/markdown/Example.cs
rename to exercises/practice/markdown/Example.cs
diff --git a/exercises/markdown/Markdown.cs b/exercises/practice/markdown/Markdown.cs
similarity index 100%
rename from exercises/markdown/Markdown.cs
rename to exercises/practice/markdown/Markdown.cs
diff --git a/exercises/markdown/Markdown.csproj b/exercises/practice/markdown/Markdown.csproj
similarity index 100%
rename from exercises/markdown/Markdown.csproj
rename to exercises/practice/markdown/Markdown.csproj
diff --git a/exercises/markdown/MarkdownTests.cs b/exercises/practice/markdown/MarkdownTests.cs
similarity index 100%
rename from exercises/markdown/MarkdownTests.cs
rename to exercises/practice/markdown/MarkdownTests.cs
diff --git a/exercises/markdown/README.md b/exercises/practice/markdown/README.md
similarity index 100%
rename from exercises/markdown/README.md
rename to exercises/practice/markdown/README.md
diff --git a/exercises/matching-brackets/.editorconfig b/exercises/practice/matching-brackets/.editorconfig
similarity index 100%
rename from exercises/matching-brackets/.editorconfig
rename to exercises/practice/matching-brackets/.editorconfig
diff --git a/exercises/matching-brackets/.meta/tests.toml b/exercises/practice/matching-brackets/.meta/tests.toml
similarity index 100%
rename from exercises/matching-brackets/.meta/tests.toml
rename to exercises/practice/matching-brackets/.meta/tests.toml
diff --git a/exercises/matching-brackets/Example.cs b/exercises/practice/matching-brackets/Example.cs
similarity index 100%
rename from exercises/matching-brackets/Example.cs
rename to exercises/practice/matching-brackets/Example.cs
diff --git a/exercises/matching-brackets/MatchingBrackets.cs b/exercises/practice/matching-brackets/MatchingBrackets.cs
similarity index 100%
rename from exercises/matching-brackets/MatchingBrackets.cs
rename to exercises/practice/matching-brackets/MatchingBrackets.cs
diff --git a/exercises/matching-brackets/MatchingBrackets.csproj b/exercises/practice/matching-brackets/MatchingBrackets.csproj
similarity index 100%
rename from exercises/matching-brackets/MatchingBrackets.csproj
rename to exercises/practice/matching-brackets/MatchingBrackets.csproj
diff --git a/exercises/matching-brackets/MatchingBracketsTests.cs b/exercises/practice/matching-brackets/MatchingBracketsTests.cs
similarity index 100%
rename from exercises/matching-brackets/MatchingBracketsTests.cs
rename to exercises/practice/matching-brackets/MatchingBracketsTests.cs
diff --git a/exercises/matching-brackets/README.md b/exercises/practice/matching-brackets/README.md
similarity index 100%
rename from exercises/matching-brackets/README.md
rename to exercises/practice/matching-brackets/README.md
diff --git a/exercises/matrix/.editorconfig b/exercises/practice/matrix/.editorconfig
similarity index 100%
rename from exercises/matrix/.editorconfig
rename to exercises/practice/matrix/.editorconfig
diff --git a/exercises/matrix/.meta/tests.toml b/exercises/practice/matrix/.meta/tests.toml
similarity index 100%
rename from exercises/matrix/.meta/tests.toml
rename to exercises/practice/matrix/.meta/tests.toml
diff --git a/exercises/matrix/Example.cs b/exercises/practice/matrix/Example.cs
similarity index 100%
rename from exercises/matrix/Example.cs
rename to exercises/practice/matrix/Example.cs
diff --git a/exercises/matrix/Matrix.cs b/exercises/practice/matrix/Matrix.cs
similarity index 100%
rename from exercises/matrix/Matrix.cs
rename to exercises/practice/matrix/Matrix.cs
diff --git a/exercises/matrix/Matrix.csproj b/exercises/practice/matrix/Matrix.csproj
similarity index 100%
rename from exercises/matrix/Matrix.csproj
rename to exercises/practice/matrix/Matrix.csproj
diff --git a/exercises/matrix/MatrixTests.cs b/exercises/practice/matrix/MatrixTests.cs
similarity index 100%
rename from exercises/matrix/MatrixTests.cs
rename to exercises/practice/matrix/MatrixTests.cs
diff --git a/exercises/matrix/README.md b/exercises/practice/matrix/README.md
similarity index 100%
rename from exercises/matrix/README.md
rename to exercises/practice/matrix/README.md
diff --git a/exercises/meetup/.editorconfig b/exercises/practice/meetup/.editorconfig
similarity index 100%
rename from exercises/meetup/.editorconfig
rename to exercises/practice/meetup/.editorconfig
diff --git a/exercises/meetup/.meta/tests.toml b/exercises/practice/meetup/.meta/tests.toml
similarity index 100%
rename from exercises/meetup/.meta/tests.toml
rename to exercises/practice/meetup/.meta/tests.toml
diff --git a/exercises/meetup/Example.cs b/exercises/practice/meetup/Example.cs
similarity index 100%
rename from exercises/meetup/Example.cs
rename to exercises/practice/meetup/Example.cs
diff --git a/exercises/meetup/Meetup.cs b/exercises/practice/meetup/Meetup.cs
similarity index 100%
rename from exercises/meetup/Meetup.cs
rename to exercises/practice/meetup/Meetup.cs
diff --git a/exercises/meetup/Meetup.csproj b/exercises/practice/meetup/Meetup.csproj
similarity index 100%
rename from exercises/meetup/Meetup.csproj
rename to exercises/practice/meetup/Meetup.csproj
diff --git a/exercises/meetup/MeetupTests.cs b/exercises/practice/meetup/MeetupTests.cs
similarity index 100%
rename from exercises/meetup/MeetupTests.cs
rename to exercises/practice/meetup/MeetupTests.cs
diff --git a/exercises/meetup/README.md b/exercises/practice/meetup/README.md
similarity index 100%
rename from exercises/meetup/README.md
rename to exercises/practice/meetup/README.md
diff --git a/exercises/minesweeper/.editorconfig b/exercises/practice/minesweeper/.editorconfig
similarity index 100%
rename from exercises/minesweeper/.editorconfig
rename to exercises/practice/minesweeper/.editorconfig
diff --git a/exercises/minesweeper/.meta/tests.toml b/exercises/practice/minesweeper/.meta/tests.toml
similarity index 100%
rename from exercises/minesweeper/.meta/tests.toml
rename to exercises/practice/minesweeper/.meta/tests.toml
diff --git a/exercises/minesweeper/Example.cs b/exercises/practice/minesweeper/Example.cs
similarity index 100%
rename from exercises/minesweeper/Example.cs
rename to exercises/practice/minesweeper/Example.cs
diff --git a/exercises/minesweeper/Minesweeper.cs b/exercises/practice/minesweeper/Minesweeper.cs
similarity index 100%
rename from exercises/minesweeper/Minesweeper.cs
rename to exercises/practice/minesweeper/Minesweeper.cs
diff --git a/exercises/minesweeper/Minesweeper.csproj b/exercises/practice/minesweeper/Minesweeper.csproj
similarity index 100%
rename from exercises/minesweeper/Minesweeper.csproj
rename to exercises/practice/minesweeper/Minesweeper.csproj
diff --git a/exercises/minesweeper/MinesweeperTests.cs b/exercises/practice/minesweeper/MinesweeperTests.cs
similarity index 100%
rename from exercises/minesweeper/MinesweeperTests.cs
rename to exercises/practice/minesweeper/MinesweeperTests.cs
diff --git a/exercises/minesweeper/README.md b/exercises/practice/minesweeper/README.md
similarity index 100%
rename from exercises/minesweeper/README.md
rename to exercises/practice/minesweeper/README.md
diff --git a/exercises/nth-prime/.editorconfig b/exercises/practice/nth-prime/.editorconfig
similarity index 100%
rename from exercises/nth-prime/.editorconfig
rename to exercises/practice/nth-prime/.editorconfig
diff --git a/exercises/nth-prime/.meta/hints.md b/exercises/practice/nth-prime/.meta/hints.md
similarity index 100%
rename from exercises/nth-prime/.meta/hints.md
rename to exercises/practice/nth-prime/.meta/hints.md
diff --git a/exercises/nth-prime/.meta/tests.toml b/exercises/practice/nth-prime/.meta/tests.toml
similarity index 100%
rename from exercises/nth-prime/.meta/tests.toml
rename to exercises/practice/nth-prime/.meta/tests.toml
diff --git a/exercises/nth-prime/Example.cs b/exercises/practice/nth-prime/Example.cs
similarity index 100%
rename from exercises/nth-prime/Example.cs
rename to exercises/practice/nth-prime/Example.cs
diff --git a/exercises/nth-prime/NthPrime.cs b/exercises/practice/nth-prime/NthPrime.cs
similarity index 100%
rename from exercises/nth-prime/NthPrime.cs
rename to exercises/practice/nth-prime/NthPrime.cs
diff --git a/exercises/nth-prime/NthPrime.csproj b/exercises/practice/nth-prime/NthPrime.csproj
similarity index 100%
rename from exercises/nth-prime/NthPrime.csproj
rename to exercises/practice/nth-prime/NthPrime.csproj
diff --git a/exercises/nth-prime/NthPrimeTests.cs b/exercises/practice/nth-prime/NthPrimeTests.cs
similarity index 100%
rename from exercises/nth-prime/NthPrimeTests.cs
rename to exercises/practice/nth-prime/NthPrimeTests.cs
diff --git a/exercises/nth-prime/README.md b/exercises/practice/nth-prime/README.md
similarity index 100%
rename from exercises/nth-prime/README.md
rename to exercises/practice/nth-prime/README.md
diff --git a/exercises/nucleotide-count/.editorconfig b/exercises/practice/nucleotide-count/.editorconfig
similarity index 100%
rename from exercises/nucleotide-count/.editorconfig
rename to exercises/practice/nucleotide-count/.editorconfig
diff --git a/exercises/nucleotide-count/.meta/hints.md b/exercises/practice/nucleotide-count/.meta/hints.md
similarity index 100%
rename from exercises/nucleotide-count/.meta/hints.md
rename to exercises/practice/nucleotide-count/.meta/hints.md
diff --git a/exercises/nucleotide-count/.meta/tests.toml b/exercises/practice/nucleotide-count/.meta/tests.toml
similarity index 100%
rename from exercises/nucleotide-count/.meta/tests.toml
rename to exercises/practice/nucleotide-count/.meta/tests.toml
diff --git a/exercises/nucleotide-count/Example.cs b/exercises/practice/nucleotide-count/Example.cs
similarity index 100%
rename from exercises/nucleotide-count/Example.cs
rename to exercises/practice/nucleotide-count/Example.cs
diff --git a/exercises/nucleotide-count/NucleotideCount.cs b/exercises/practice/nucleotide-count/NucleotideCount.cs
similarity index 100%
rename from exercises/nucleotide-count/NucleotideCount.cs
rename to exercises/practice/nucleotide-count/NucleotideCount.cs
diff --git a/exercises/nucleotide-count/NucleotideCount.csproj b/exercises/practice/nucleotide-count/NucleotideCount.csproj
similarity index 100%
rename from exercises/nucleotide-count/NucleotideCount.csproj
rename to exercises/practice/nucleotide-count/NucleotideCount.csproj
diff --git a/exercises/nucleotide-count/NucleotideCountTests.cs b/exercises/practice/nucleotide-count/NucleotideCountTests.cs
similarity index 100%
rename from exercises/nucleotide-count/NucleotideCountTests.cs
rename to exercises/practice/nucleotide-count/NucleotideCountTests.cs
diff --git a/exercises/nucleotide-count/README.md b/exercises/practice/nucleotide-count/README.md
similarity index 100%
rename from exercises/nucleotide-count/README.md
rename to exercises/practice/nucleotide-count/README.md
diff --git a/exercises/ocr-numbers/.editorconfig b/exercises/practice/ocr-numbers/.editorconfig
similarity index 100%
rename from exercises/ocr-numbers/.editorconfig
rename to exercises/practice/ocr-numbers/.editorconfig
diff --git a/exercises/ocr-numbers/.meta/tests.toml b/exercises/practice/ocr-numbers/.meta/tests.toml
similarity index 100%
rename from exercises/ocr-numbers/.meta/tests.toml
rename to exercises/practice/ocr-numbers/.meta/tests.toml
diff --git a/exercises/ocr-numbers/Example.cs b/exercises/practice/ocr-numbers/Example.cs
similarity index 100%
rename from exercises/ocr-numbers/Example.cs
rename to exercises/practice/ocr-numbers/Example.cs
diff --git a/exercises/ocr-numbers/OcrNumbers.cs b/exercises/practice/ocr-numbers/OcrNumbers.cs
similarity index 100%
rename from exercises/ocr-numbers/OcrNumbers.cs
rename to exercises/practice/ocr-numbers/OcrNumbers.cs
diff --git a/exercises/ocr-numbers/OcrNumbers.csproj b/exercises/practice/ocr-numbers/OcrNumbers.csproj
similarity index 100%
rename from exercises/ocr-numbers/OcrNumbers.csproj
rename to exercises/practice/ocr-numbers/OcrNumbers.csproj
diff --git a/exercises/ocr-numbers/OcrNumbersTests.cs b/exercises/practice/ocr-numbers/OcrNumbersTests.cs
similarity index 100%
rename from exercises/ocr-numbers/OcrNumbersTests.cs
rename to exercises/practice/ocr-numbers/OcrNumbersTests.cs
diff --git a/exercises/ocr-numbers/README.md b/exercises/practice/ocr-numbers/README.md
similarity index 100%
rename from exercises/ocr-numbers/README.md
rename to exercises/practice/ocr-numbers/README.md
diff --git a/exercises/octal/.editorconfig b/exercises/practice/octal/.editorconfig
similarity index 100%
rename from exercises/octal/.editorconfig
rename to exercises/practice/octal/.editorconfig
diff --git a/exercises/octal/Example.cs b/exercises/practice/octal/Example.cs
similarity index 100%
rename from exercises/octal/Example.cs
rename to exercises/practice/octal/Example.cs
diff --git a/exercises/octal/Octal.cs b/exercises/practice/octal/Octal.cs
similarity index 100%
rename from exercises/octal/Octal.cs
rename to exercises/practice/octal/Octal.cs
diff --git a/exercises/octal/Octal.csproj b/exercises/practice/octal/Octal.csproj
similarity index 100%
rename from exercises/octal/Octal.csproj
rename to exercises/practice/octal/Octal.csproj
diff --git a/exercises/octal/OctalTests.cs b/exercises/practice/octal/OctalTests.cs
similarity index 100%
rename from exercises/octal/OctalTests.cs
rename to exercises/practice/octal/OctalTests.cs
diff --git a/exercises/octal/README.md b/exercises/practice/octal/README.md
similarity index 100%
rename from exercises/octal/README.md
rename to exercises/practice/octal/README.md
diff --git a/exercises/palindrome-products/.editorconfig b/exercises/practice/palindrome-products/.editorconfig
similarity index 100%
rename from exercises/palindrome-products/.editorconfig
rename to exercises/practice/palindrome-products/.editorconfig
diff --git a/exercises/palindrome-products/.meta/hints.md b/exercises/practice/palindrome-products/.meta/hints.md
similarity index 100%
rename from exercises/palindrome-products/.meta/hints.md
rename to exercises/practice/palindrome-products/.meta/hints.md
diff --git a/exercises/palindrome-products/.meta/tests.toml b/exercises/practice/palindrome-products/.meta/tests.toml
similarity index 100%
rename from exercises/palindrome-products/.meta/tests.toml
rename to exercises/practice/palindrome-products/.meta/tests.toml
diff --git a/exercises/palindrome-products/Example.cs b/exercises/practice/palindrome-products/Example.cs
similarity index 100%
rename from exercises/palindrome-products/Example.cs
rename to exercises/practice/palindrome-products/Example.cs
diff --git a/exercises/palindrome-products/PalindromeProducts.cs b/exercises/practice/palindrome-products/PalindromeProducts.cs
similarity index 100%
rename from exercises/palindrome-products/PalindromeProducts.cs
rename to exercises/practice/palindrome-products/PalindromeProducts.cs
diff --git a/exercises/palindrome-products/PalindromeProducts.csproj b/exercises/practice/palindrome-products/PalindromeProducts.csproj
similarity index 100%
rename from exercises/palindrome-products/PalindromeProducts.csproj
rename to exercises/practice/palindrome-products/PalindromeProducts.csproj
diff --git a/exercises/palindrome-products/PalindromeProductsTests.cs b/exercises/practice/palindrome-products/PalindromeProductsTests.cs
similarity index 100%
rename from exercises/palindrome-products/PalindromeProductsTests.cs
rename to exercises/practice/palindrome-products/PalindromeProductsTests.cs
diff --git a/exercises/palindrome-products/README.md b/exercises/practice/palindrome-products/README.md
similarity index 100%
rename from exercises/palindrome-products/README.md
rename to exercises/practice/palindrome-products/README.md
diff --git a/exercises/pangram/.editorconfig b/exercises/practice/pangram/.editorconfig
similarity index 100%
rename from exercises/pangram/.editorconfig
rename to exercises/practice/pangram/.editorconfig
diff --git a/exercises/pangram/.meta/tests.toml b/exercises/practice/pangram/.meta/tests.toml
similarity index 100%
rename from exercises/pangram/.meta/tests.toml
rename to exercises/practice/pangram/.meta/tests.toml
diff --git a/exercises/pangram/Example.cs b/exercises/practice/pangram/Example.cs
similarity index 100%
rename from exercises/pangram/Example.cs
rename to exercises/practice/pangram/Example.cs
diff --git a/exercises/pangram/Pangram.cs b/exercises/practice/pangram/Pangram.cs
similarity index 100%
rename from exercises/pangram/Pangram.cs
rename to exercises/practice/pangram/Pangram.cs
diff --git a/exercises/pangram/Pangram.csproj b/exercises/practice/pangram/Pangram.csproj
similarity index 100%
rename from exercises/pangram/Pangram.csproj
rename to exercises/practice/pangram/Pangram.csproj
diff --git a/exercises/pangram/PangramTests.cs b/exercises/practice/pangram/PangramTests.cs
similarity index 100%
rename from exercises/pangram/PangramTests.cs
rename to exercises/practice/pangram/PangramTests.cs
diff --git a/exercises/pangram/README.md b/exercises/practice/pangram/README.md
similarity index 100%
rename from exercises/pangram/README.md
rename to exercises/practice/pangram/README.md
diff --git a/exercises/parallel-letter-frequency/.editorconfig b/exercises/practice/parallel-letter-frequency/.editorconfig
similarity index 100%
rename from exercises/parallel-letter-frequency/.editorconfig
rename to exercises/practice/parallel-letter-frequency/.editorconfig
diff --git a/exercises/parallel-letter-frequency/Example.cs b/exercises/practice/parallel-letter-frequency/Example.cs
similarity index 100%
rename from exercises/parallel-letter-frequency/Example.cs
rename to exercises/practice/parallel-letter-frequency/Example.cs
diff --git a/exercises/parallel-letter-frequency/ParallelLetterFrequency.cs b/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.cs
similarity index 100%
rename from exercises/parallel-letter-frequency/ParallelLetterFrequency.cs
rename to exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.cs
diff --git a/exercises/parallel-letter-frequency/ParallelLetterFrequency.csproj b/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj
similarity index 100%
rename from exercises/parallel-letter-frequency/ParallelLetterFrequency.csproj
rename to exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj
diff --git a/exercises/parallel-letter-frequency/ParallelLetterFrequencyTests.cs b/exercises/practice/parallel-letter-frequency/ParallelLetterFrequencyTests.cs
similarity index 100%
rename from exercises/parallel-letter-frequency/ParallelLetterFrequencyTests.cs
rename to exercises/practice/parallel-letter-frequency/ParallelLetterFrequencyTests.cs
diff --git a/exercises/parallel-letter-frequency/README.md b/exercises/practice/parallel-letter-frequency/README.md
similarity index 100%
rename from exercises/parallel-letter-frequency/README.md
rename to exercises/practice/parallel-letter-frequency/README.md
diff --git a/exercises/pascals-triangle/.editorconfig b/exercises/practice/pascals-triangle/.editorconfig
similarity index 100%
rename from exercises/pascals-triangle/.editorconfig
rename to exercises/practice/pascals-triangle/.editorconfig
diff --git a/exercises/pascals-triangle/.meta/tests.toml b/exercises/practice/pascals-triangle/.meta/tests.toml
similarity index 100%
rename from exercises/pascals-triangle/.meta/tests.toml
rename to exercises/practice/pascals-triangle/.meta/tests.toml
diff --git a/exercises/pascals-triangle/Example.cs b/exercises/practice/pascals-triangle/Example.cs
similarity index 100%
rename from exercises/pascals-triangle/Example.cs
rename to exercises/practice/pascals-triangle/Example.cs
diff --git a/exercises/pascals-triangle/PascalsTriangle.cs b/exercises/practice/pascals-triangle/PascalsTriangle.cs
similarity index 100%
rename from exercises/pascals-triangle/PascalsTriangle.cs
rename to exercises/practice/pascals-triangle/PascalsTriangle.cs
diff --git a/exercises/pascals-triangle/PascalsTriangle.csproj b/exercises/practice/pascals-triangle/PascalsTriangle.csproj
similarity index 100%
rename from exercises/pascals-triangle/PascalsTriangle.csproj
rename to exercises/practice/pascals-triangle/PascalsTriangle.csproj
diff --git a/exercises/pascals-triangle/PascalsTriangleTests.cs b/exercises/practice/pascals-triangle/PascalsTriangleTests.cs
similarity index 100%
rename from exercises/pascals-triangle/PascalsTriangleTests.cs
rename to exercises/practice/pascals-triangle/PascalsTriangleTests.cs
diff --git a/exercises/pascals-triangle/README.md b/exercises/practice/pascals-triangle/README.md
similarity index 100%
rename from exercises/pascals-triangle/README.md
rename to exercises/practice/pascals-triangle/README.md
diff --git a/exercises/perfect-numbers/.editorconfig b/exercises/practice/perfect-numbers/.editorconfig
similarity index 100%
rename from exercises/perfect-numbers/.editorconfig
rename to exercises/practice/perfect-numbers/.editorconfig
diff --git a/exercises/perfect-numbers/.meta/tests.toml b/exercises/practice/perfect-numbers/.meta/tests.toml
similarity index 100%
rename from exercises/perfect-numbers/.meta/tests.toml
rename to exercises/practice/perfect-numbers/.meta/tests.toml
diff --git a/exercises/perfect-numbers/Example.cs b/exercises/practice/perfect-numbers/Example.cs
similarity index 100%
rename from exercises/perfect-numbers/Example.cs
rename to exercises/practice/perfect-numbers/Example.cs
diff --git a/exercises/perfect-numbers/PerfectNumbers.cs b/exercises/practice/perfect-numbers/PerfectNumbers.cs
similarity index 100%
rename from exercises/perfect-numbers/PerfectNumbers.cs
rename to exercises/practice/perfect-numbers/PerfectNumbers.cs
diff --git a/exercises/perfect-numbers/PerfectNumbers.csproj b/exercises/practice/perfect-numbers/PerfectNumbers.csproj
similarity index 100%
rename from exercises/perfect-numbers/PerfectNumbers.csproj
rename to exercises/practice/perfect-numbers/PerfectNumbers.csproj
diff --git a/exercises/perfect-numbers/PerfectNumbersTests.cs b/exercises/practice/perfect-numbers/PerfectNumbersTests.cs
similarity index 100%
rename from exercises/perfect-numbers/PerfectNumbersTests.cs
rename to exercises/practice/perfect-numbers/PerfectNumbersTests.cs
diff --git a/exercises/perfect-numbers/README.md b/exercises/practice/perfect-numbers/README.md
similarity index 100%
rename from exercises/perfect-numbers/README.md
rename to exercises/practice/perfect-numbers/README.md
diff --git a/exercises/phone-number/.editorconfig b/exercises/practice/phone-number/.editorconfig
similarity index 100%
rename from exercises/phone-number/.editorconfig
rename to exercises/practice/phone-number/.editorconfig
diff --git a/exercises/phone-number/.meta/tests.toml b/exercises/practice/phone-number/.meta/tests.toml
similarity index 100%
rename from exercises/phone-number/.meta/tests.toml
rename to exercises/practice/phone-number/.meta/tests.toml
diff --git a/exercises/phone-number/Example.cs b/exercises/practice/phone-number/Example.cs
similarity index 100%
rename from exercises/phone-number/Example.cs
rename to exercises/practice/phone-number/Example.cs
diff --git a/exercises/phone-number/PhoneNumber.cs b/exercises/practice/phone-number/PhoneNumber.cs
similarity index 100%
rename from exercises/phone-number/PhoneNumber.cs
rename to exercises/practice/phone-number/PhoneNumber.cs
diff --git a/exercises/phone-number/PhoneNumber.csproj b/exercises/practice/phone-number/PhoneNumber.csproj
similarity index 100%
rename from exercises/phone-number/PhoneNumber.csproj
rename to exercises/practice/phone-number/PhoneNumber.csproj
diff --git a/exercises/phone-number/PhoneNumberTests.cs b/exercises/practice/phone-number/PhoneNumberTests.cs
similarity index 100%
rename from exercises/phone-number/PhoneNumberTests.cs
rename to exercises/practice/phone-number/PhoneNumberTests.cs
diff --git a/exercises/phone-number/README.md b/exercises/practice/phone-number/README.md
similarity index 100%
rename from exercises/phone-number/README.md
rename to exercises/practice/phone-number/README.md
diff --git a/exercises/pig-latin/.editorconfig b/exercises/practice/pig-latin/.editorconfig
similarity index 100%
rename from exercises/pig-latin/.editorconfig
rename to exercises/practice/pig-latin/.editorconfig
diff --git a/exercises/pig-latin/.meta/tests.toml b/exercises/practice/pig-latin/.meta/tests.toml
similarity index 100%
rename from exercises/pig-latin/.meta/tests.toml
rename to exercises/practice/pig-latin/.meta/tests.toml
diff --git a/exercises/pig-latin/Example.cs b/exercises/practice/pig-latin/Example.cs
similarity index 100%
rename from exercises/pig-latin/Example.cs
rename to exercises/practice/pig-latin/Example.cs
diff --git a/exercises/pig-latin/PigLatin.cs b/exercises/practice/pig-latin/PigLatin.cs
similarity index 100%
rename from exercises/pig-latin/PigLatin.cs
rename to exercises/practice/pig-latin/PigLatin.cs
diff --git a/exercises/pig-latin/PigLatin.csproj b/exercises/practice/pig-latin/PigLatin.csproj
similarity index 100%
rename from exercises/pig-latin/PigLatin.csproj
rename to exercises/practice/pig-latin/PigLatin.csproj
diff --git a/exercises/pig-latin/PigLatinTests.cs b/exercises/practice/pig-latin/PigLatinTests.cs
similarity index 100%
rename from exercises/pig-latin/PigLatinTests.cs
rename to exercises/practice/pig-latin/PigLatinTests.cs
diff --git a/exercises/pig-latin/README.md b/exercises/practice/pig-latin/README.md
similarity index 100%
rename from exercises/pig-latin/README.md
rename to exercises/practice/pig-latin/README.md
diff --git a/exercises/poker/.editorconfig b/exercises/practice/poker/.editorconfig
similarity index 100%
rename from exercises/poker/.editorconfig
rename to exercises/practice/poker/.editorconfig
diff --git a/exercises/poker/.meta/tests.toml b/exercises/practice/poker/.meta/tests.toml
similarity index 100%
rename from exercises/poker/.meta/tests.toml
rename to exercises/practice/poker/.meta/tests.toml
diff --git a/exercises/poker/Example.cs b/exercises/practice/poker/Example.cs
similarity index 100%
rename from exercises/poker/Example.cs
rename to exercises/practice/poker/Example.cs
diff --git a/exercises/poker/Poker.cs b/exercises/practice/poker/Poker.cs
similarity index 100%
rename from exercises/poker/Poker.cs
rename to exercises/practice/poker/Poker.cs
diff --git a/exercises/poker/Poker.csproj b/exercises/practice/poker/Poker.csproj
similarity index 100%
rename from exercises/poker/Poker.csproj
rename to exercises/practice/poker/Poker.csproj
diff --git a/exercises/poker/PokerTests.cs b/exercises/practice/poker/PokerTests.cs
similarity index 100%
rename from exercises/poker/PokerTests.cs
rename to exercises/practice/poker/PokerTests.cs
diff --git a/exercises/poker/README.md b/exercises/practice/poker/README.md
similarity index 100%
rename from exercises/poker/README.md
rename to exercises/practice/poker/README.md
diff --git a/exercises/pov/.editorconfig b/exercises/practice/pov/.editorconfig
similarity index 100%
rename from exercises/pov/.editorconfig
rename to exercises/practice/pov/.editorconfig
diff --git a/exercises/pov/.meta/tests.toml b/exercises/practice/pov/.meta/tests.toml
similarity index 100%
rename from exercises/pov/.meta/tests.toml
rename to exercises/practice/pov/.meta/tests.toml
diff --git a/exercises/pov/Example.cs b/exercises/practice/pov/Example.cs
similarity index 100%
rename from exercises/pov/Example.cs
rename to exercises/practice/pov/Example.cs
diff --git a/exercises/pov/Pov.cs b/exercises/practice/pov/Pov.cs
similarity index 100%
rename from exercises/pov/Pov.cs
rename to exercises/practice/pov/Pov.cs
diff --git a/exercises/pov/Pov.csproj b/exercises/practice/pov/Pov.csproj
similarity index 100%
rename from exercises/pov/Pov.csproj
rename to exercises/practice/pov/Pov.csproj
diff --git a/exercises/pov/PovTests.cs b/exercises/practice/pov/PovTests.cs
similarity index 100%
rename from exercises/pov/PovTests.cs
rename to exercises/practice/pov/PovTests.cs
diff --git a/exercises/pov/README.md b/exercises/practice/pov/README.md
similarity index 100%
rename from exercises/pov/README.md
rename to exercises/practice/pov/README.md
diff --git a/exercises/prime-factors/.editorconfig b/exercises/practice/prime-factors/.editorconfig
similarity index 100%
rename from exercises/prime-factors/.editorconfig
rename to exercises/practice/prime-factors/.editorconfig
diff --git a/exercises/prime-factors/.meta/tests.toml b/exercises/practice/prime-factors/.meta/tests.toml
similarity index 100%
rename from exercises/prime-factors/.meta/tests.toml
rename to exercises/practice/prime-factors/.meta/tests.toml
diff --git a/exercises/prime-factors/Example.cs b/exercises/practice/prime-factors/Example.cs
similarity index 100%
rename from exercises/prime-factors/Example.cs
rename to exercises/practice/prime-factors/Example.cs
diff --git a/exercises/prime-factors/PrimeFactors.cs b/exercises/practice/prime-factors/PrimeFactors.cs
similarity index 100%
rename from exercises/prime-factors/PrimeFactors.cs
rename to exercises/practice/prime-factors/PrimeFactors.cs
diff --git a/exercises/prime-factors/PrimeFactors.csproj b/exercises/practice/prime-factors/PrimeFactors.csproj
similarity index 100%
rename from exercises/prime-factors/PrimeFactors.csproj
rename to exercises/practice/prime-factors/PrimeFactors.csproj
diff --git a/exercises/prime-factors/PrimeFactorsTests.cs b/exercises/practice/prime-factors/PrimeFactorsTests.cs
similarity index 100%
rename from exercises/prime-factors/PrimeFactorsTests.cs
rename to exercises/practice/prime-factors/PrimeFactorsTests.cs
diff --git a/exercises/prime-factors/README.md b/exercises/practice/prime-factors/README.md
similarity index 100%
rename from exercises/prime-factors/README.md
rename to exercises/practice/prime-factors/README.md
diff --git a/exercises/protein-translation/.editorconfig b/exercises/practice/protein-translation/.editorconfig
similarity index 100%
rename from exercises/protein-translation/.editorconfig
rename to exercises/practice/protein-translation/.editorconfig
diff --git a/exercises/protein-translation/.meta/tests.toml b/exercises/practice/protein-translation/.meta/tests.toml
similarity index 100%
rename from exercises/protein-translation/.meta/tests.toml
rename to exercises/practice/protein-translation/.meta/tests.toml
diff --git a/exercises/protein-translation/Example.cs b/exercises/practice/protein-translation/Example.cs
similarity index 100%
rename from exercises/protein-translation/Example.cs
rename to exercises/practice/protein-translation/Example.cs
diff --git a/exercises/protein-translation/ProteinTranslation.cs b/exercises/practice/protein-translation/ProteinTranslation.cs
similarity index 100%
rename from exercises/protein-translation/ProteinTranslation.cs
rename to exercises/practice/protein-translation/ProteinTranslation.cs
diff --git a/exercises/protein-translation/ProteinTranslation.csproj b/exercises/practice/protein-translation/ProteinTranslation.csproj
similarity index 100%
rename from exercises/protein-translation/ProteinTranslation.csproj
rename to exercises/practice/protein-translation/ProteinTranslation.csproj
diff --git a/exercises/protein-translation/ProteinTranslationTests.cs b/exercises/practice/protein-translation/ProteinTranslationTests.cs
similarity index 100%
rename from exercises/protein-translation/ProteinTranslationTests.cs
rename to exercises/practice/protein-translation/ProteinTranslationTests.cs
diff --git a/exercises/protein-translation/README.md b/exercises/practice/protein-translation/README.md
similarity index 100%
rename from exercises/protein-translation/README.md
rename to exercises/practice/protein-translation/README.md
diff --git a/exercises/proverb/.editorconfig b/exercises/practice/proverb/.editorconfig
similarity index 100%
rename from exercises/proverb/.editorconfig
rename to exercises/practice/proverb/.editorconfig
diff --git a/exercises/proverb/.meta/hints.md b/exercises/practice/proverb/.meta/hints.md
similarity index 100%
rename from exercises/proverb/.meta/hints.md
rename to exercises/practice/proverb/.meta/hints.md
diff --git a/exercises/proverb/.meta/tests.toml b/exercises/practice/proverb/.meta/tests.toml
similarity index 100%
rename from exercises/proverb/.meta/tests.toml
rename to exercises/practice/proverb/.meta/tests.toml
diff --git a/exercises/proverb/Example.cs b/exercises/practice/proverb/Example.cs
similarity index 100%
rename from exercises/proverb/Example.cs
rename to exercises/practice/proverb/Example.cs
diff --git a/exercises/proverb/Proverb.cs b/exercises/practice/proverb/Proverb.cs
similarity index 100%
rename from exercises/proverb/Proverb.cs
rename to exercises/practice/proverb/Proverb.cs
diff --git a/exercises/proverb/Proverb.csproj b/exercises/practice/proverb/Proverb.csproj
similarity index 100%
rename from exercises/proverb/Proverb.csproj
rename to exercises/practice/proverb/Proverb.csproj
diff --git a/exercises/proverb/ProverbTests.cs b/exercises/practice/proverb/ProverbTests.cs
similarity index 100%
rename from exercises/proverb/ProverbTests.cs
rename to exercises/practice/proverb/ProverbTests.cs
diff --git a/exercises/proverb/README.md b/exercises/practice/proverb/README.md
similarity index 100%
rename from exercises/proverb/README.md
rename to exercises/practice/proverb/README.md
diff --git a/exercises/pythagorean-triplet/.editorconfig b/exercises/practice/pythagorean-triplet/.editorconfig
similarity index 100%
rename from exercises/pythagorean-triplet/.editorconfig
rename to exercises/practice/pythagorean-triplet/.editorconfig
diff --git a/exercises/pythagorean-triplet/.meta/tests.toml b/exercises/practice/pythagorean-triplet/.meta/tests.toml
similarity index 100%
rename from exercises/pythagorean-triplet/.meta/tests.toml
rename to exercises/practice/pythagorean-triplet/.meta/tests.toml
diff --git a/exercises/pythagorean-triplet/Example.cs b/exercises/practice/pythagorean-triplet/Example.cs
similarity index 100%
rename from exercises/pythagorean-triplet/Example.cs
rename to exercises/practice/pythagorean-triplet/Example.cs
diff --git a/exercises/pythagorean-triplet/PythagoreanTriplet.cs b/exercises/practice/pythagorean-triplet/PythagoreanTriplet.cs
similarity index 100%
rename from exercises/pythagorean-triplet/PythagoreanTriplet.cs
rename to exercises/practice/pythagorean-triplet/PythagoreanTriplet.cs
diff --git a/exercises/pythagorean-triplet/PythagoreanTriplet.csproj b/exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj
similarity index 100%
rename from exercises/pythagorean-triplet/PythagoreanTriplet.csproj
rename to exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj
diff --git a/exercises/pythagorean-triplet/PythagoreanTripletTests.cs b/exercises/practice/pythagorean-triplet/PythagoreanTripletTests.cs
similarity index 100%
rename from exercises/pythagorean-triplet/PythagoreanTripletTests.cs
rename to exercises/practice/pythagorean-triplet/PythagoreanTripletTests.cs
diff --git a/exercises/pythagorean-triplet/README.md b/exercises/practice/pythagorean-triplet/README.md
similarity index 100%
rename from exercises/pythagorean-triplet/README.md
rename to exercises/practice/pythagorean-triplet/README.md
diff --git a/exercises/queen-attack/.editorconfig b/exercises/practice/queen-attack/.editorconfig
similarity index 100%
rename from exercises/queen-attack/.editorconfig
rename to exercises/practice/queen-attack/.editorconfig
diff --git a/exercises/queen-attack/.meta/tests.toml b/exercises/practice/queen-attack/.meta/tests.toml
similarity index 100%
rename from exercises/queen-attack/.meta/tests.toml
rename to exercises/practice/queen-attack/.meta/tests.toml
diff --git a/exercises/queen-attack/Example.cs b/exercises/practice/queen-attack/Example.cs
similarity index 100%
rename from exercises/queen-attack/Example.cs
rename to exercises/practice/queen-attack/Example.cs
diff --git a/exercises/queen-attack/QueenAttack.cs b/exercises/practice/queen-attack/QueenAttack.cs
similarity index 100%
rename from exercises/queen-attack/QueenAttack.cs
rename to exercises/practice/queen-attack/QueenAttack.cs
diff --git a/exercises/queen-attack/QueenAttack.csproj b/exercises/practice/queen-attack/QueenAttack.csproj
similarity index 100%
rename from exercises/queen-attack/QueenAttack.csproj
rename to exercises/practice/queen-attack/QueenAttack.csproj
diff --git a/exercises/queen-attack/QueenAttackTests.cs b/exercises/practice/queen-attack/QueenAttackTests.cs
similarity index 100%
rename from exercises/queen-attack/QueenAttackTests.cs
rename to exercises/practice/queen-attack/QueenAttackTests.cs
diff --git a/exercises/queen-attack/README.md b/exercises/practice/queen-attack/README.md
similarity index 100%
rename from exercises/queen-attack/README.md
rename to exercises/practice/queen-attack/README.md
diff --git a/exercises/rail-fence-cipher/.editorconfig b/exercises/practice/rail-fence-cipher/.editorconfig
similarity index 100%
rename from exercises/rail-fence-cipher/.editorconfig
rename to exercises/practice/rail-fence-cipher/.editorconfig
diff --git a/exercises/rail-fence-cipher/.meta/tests.toml b/exercises/practice/rail-fence-cipher/.meta/tests.toml
similarity index 100%
rename from exercises/rail-fence-cipher/.meta/tests.toml
rename to exercises/practice/rail-fence-cipher/.meta/tests.toml
diff --git a/exercises/rail-fence-cipher/Example.cs b/exercises/practice/rail-fence-cipher/Example.cs
similarity index 100%
rename from exercises/rail-fence-cipher/Example.cs
rename to exercises/practice/rail-fence-cipher/Example.cs
diff --git a/exercises/rail-fence-cipher/README.md b/exercises/practice/rail-fence-cipher/README.md
similarity index 100%
rename from exercises/rail-fence-cipher/README.md
rename to exercises/practice/rail-fence-cipher/README.md
diff --git a/exercises/rail-fence-cipher/RailFenceCipher.cs b/exercises/practice/rail-fence-cipher/RailFenceCipher.cs
similarity index 100%
rename from exercises/rail-fence-cipher/RailFenceCipher.cs
rename to exercises/practice/rail-fence-cipher/RailFenceCipher.cs
diff --git a/exercises/rail-fence-cipher/RailFenceCipher.csproj b/exercises/practice/rail-fence-cipher/RailFenceCipher.csproj
similarity index 100%
rename from exercises/rail-fence-cipher/RailFenceCipher.csproj
rename to exercises/practice/rail-fence-cipher/RailFenceCipher.csproj
diff --git a/exercises/rail-fence-cipher/RailFenceCipherTests.cs b/exercises/practice/rail-fence-cipher/RailFenceCipherTests.cs
similarity index 100%
rename from exercises/rail-fence-cipher/RailFenceCipherTests.cs
rename to exercises/practice/rail-fence-cipher/RailFenceCipherTests.cs
diff --git a/exercises/raindrops/.editorconfig b/exercises/practice/raindrops/.editorconfig
similarity index 100%
rename from exercises/raindrops/.editorconfig
rename to exercises/practice/raindrops/.editorconfig
diff --git a/exercises/raindrops/.meta/tests.toml b/exercises/practice/raindrops/.meta/tests.toml
similarity index 100%
rename from exercises/raindrops/.meta/tests.toml
rename to exercises/practice/raindrops/.meta/tests.toml
diff --git a/exercises/raindrops/Example.cs b/exercises/practice/raindrops/Example.cs
similarity index 100%
rename from exercises/raindrops/Example.cs
rename to exercises/practice/raindrops/Example.cs
diff --git a/exercises/raindrops/README.md b/exercises/practice/raindrops/README.md
similarity index 100%
rename from exercises/raindrops/README.md
rename to exercises/practice/raindrops/README.md
diff --git a/exercises/raindrops/Raindrops.cs b/exercises/practice/raindrops/Raindrops.cs
similarity index 100%
rename from exercises/raindrops/Raindrops.cs
rename to exercises/practice/raindrops/Raindrops.cs
diff --git a/exercises/raindrops/Raindrops.csproj b/exercises/practice/raindrops/Raindrops.csproj
similarity index 100%
rename from exercises/raindrops/Raindrops.csproj
rename to exercises/practice/raindrops/Raindrops.csproj
diff --git a/exercises/raindrops/RaindropsTests.cs b/exercises/practice/raindrops/RaindropsTests.cs
similarity index 100%
rename from exercises/raindrops/RaindropsTests.cs
rename to exercises/practice/raindrops/RaindropsTests.cs
diff --git a/exercises/rational-numbers/.editorconfig b/exercises/practice/rational-numbers/.editorconfig
similarity index 100%
rename from exercises/rational-numbers/.editorconfig
rename to exercises/practice/rational-numbers/.editorconfig
diff --git a/exercises/rational-numbers/.meta/tests.toml b/exercises/practice/rational-numbers/.meta/tests.toml
similarity index 100%
rename from exercises/rational-numbers/.meta/tests.toml
rename to exercises/practice/rational-numbers/.meta/tests.toml
diff --git a/exercises/rational-numbers/Example.cs b/exercises/practice/rational-numbers/Example.cs
similarity index 100%
rename from exercises/rational-numbers/Example.cs
rename to exercises/practice/rational-numbers/Example.cs
diff --git a/exercises/rational-numbers/README.md b/exercises/practice/rational-numbers/README.md
similarity index 100%
rename from exercises/rational-numbers/README.md
rename to exercises/practice/rational-numbers/README.md
diff --git a/exercises/rational-numbers/RationalNumbers.cs b/exercises/practice/rational-numbers/RationalNumbers.cs
similarity index 100%
rename from exercises/rational-numbers/RationalNumbers.cs
rename to exercises/practice/rational-numbers/RationalNumbers.cs
diff --git a/exercises/rational-numbers/RationalNumbers.csproj b/exercises/practice/rational-numbers/RationalNumbers.csproj
similarity index 100%
rename from exercises/rational-numbers/RationalNumbers.csproj
rename to exercises/practice/rational-numbers/RationalNumbers.csproj
diff --git a/exercises/rational-numbers/RationalNumbersTests.cs b/exercises/practice/rational-numbers/RationalNumbersTests.cs
similarity index 100%
rename from exercises/rational-numbers/RationalNumbersTests.cs
rename to exercises/practice/rational-numbers/RationalNumbersTests.cs
diff --git a/exercises/rational-numbers/hints.md b/exercises/practice/rational-numbers/hints.md
similarity index 100%
rename from exercises/rational-numbers/hints.md
rename to exercises/practice/rational-numbers/hints.md
diff --git a/exercises/react/.editorconfig b/exercises/practice/react/.editorconfig
similarity index 100%
rename from exercises/react/.editorconfig
rename to exercises/practice/react/.editorconfig
diff --git a/exercises/react/.meta/hints.md b/exercises/practice/react/.meta/hints.md
similarity index 100%
rename from exercises/react/.meta/hints.md
rename to exercises/practice/react/.meta/hints.md
diff --git a/exercises/react/.meta/tests.toml b/exercises/practice/react/.meta/tests.toml
similarity index 100%
rename from exercises/react/.meta/tests.toml
rename to exercises/practice/react/.meta/tests.toml
diff --git a/exercises/react/Example.cs b/exercises/practice/react/Example.cs
similarity index 100%
rename from exercises/react/Example.cs
rename to exercises/practice/react/Example.cs
diff --git a/exercises/react/README.md b/exercises/practice/react/README.md
similarity index 100%
rename from exercises/react/README.md
rename to exercises/practice/react/README.md
diff --git a/exercises/react/React.cs b/exercises/practice/react/React.cs
similarity index 100%
rename from exercises/react/React.cs
rename to exercises/practice/react/React.cs
diff --git a/exercises/react/React.csproj b/exercises/practice/react/React.csproj
similarity index 100%
rename from exercises/react/React.csproj
rename to exercises/practice/react/React.csproj
diff --git a/exercises/react/ReactTests.cs b/exercises/practice/react/ReactTests.cs
similarity index 100%
rename from exercises/react/ReactTests.cs
rename to exercises/practice/react/ReactTests.cs
diff --git a/exercises/rectangles/.editorconfig b/exercises/practice/rectangles/.editorconfig
similarity index 100%
rename from exercises/rectangles/.editorconfig
rename to exercises/practice/rectangles/.editorconfig
diff --git a/exercises/rectangles/.meta/tests.toml b/exercises/practice/rectangles/.meta/tests.toml
similarity index 100%
rename from exercises/rectangles/.meta/tests.toml
rename to exercises/practice/rectangles/.meta/tests.toml
diff --git a/exercises/rectangles/Example.cs b/exercises/practice/rectangles/Example.cs
similarity index 100%
rename from exercises/rectangles/Example.cs
rename to exercises/practice/rectangles/Example.cs
diff --git a/exercises/rectangles/README.md b/exercises/practice/rectangles/README.md
similarity index 100%
rename from exercises/rectangles/README.md
rename to exercises/practice/rectangles/README.md
diff --git a/exercises/rectangles/Rectangles.cs b/exercises/practice/rectangles/Rectangles.cs
similarity index 100%
rename from exercises/rectangles/Rectangles.cs
rename to exercises/practice/rectangles/Rectangles.cs
diff --git a/exercises/rectangles/Rectangles.csproj b/exercises/practice/rectangles/Rectangles.csproj
similarity index 100%
rename from exercises/rectangles/Rectangles.csproj
rename to exercises/practice/rectangles/Rectangles.csproj
diff --git a/exercises/rectangles/RectanglesTests.cs b/exercises/practice/rectangles/RectanglesTests.cs
similarity index 100%
rename from exercises/rectangles/RectanglesTests.cs
rename to exercises/practice/rectangles/RectanglesTests.cs
diff --git a/exercises/resistor-color-duo/.editorconfig b/exercises/practice/resistor-color-duo/.editorconfig
similarity index 100%
rename from exercises/resistor-color-duo/.editorconfig
rename to exercises/practice/resistor-color-duo/.editorconfig
diff --git a/exercises/resistor-color-duo/.meta/tests.toml b/exercises/practice/resistor-color-duo/.meta/tests.toml
similarity index 100%
rename from exercises/resistor-color-duo/.meta/tests.toml
rename to exercises/practice/resistor-color-duo/.meta/tests.toml
diff --git a/exercises/resistor-color-duo/Example.cs b/exercises/practice/resistor-color-duo/Example.cs
similarity index 100%
rename from exercises/resistor-color-duo/Example.cs
rename to exercises/practice/resistor-color-duo/Example.cs
diff --git a/exercises/resistor-color-duo/README.md b/exercises/practice/resistor-color-duo/README.md
similarity index 100%
rename from exercises/resistor-color-duo/README.md
rename to exercises/practice/resistor-color-duo/README.md
diff --git a/exercises/resistor-color-duo/ResistorColorDuo.cs b/exercises/practice/resistor-color-duo/ResistorColorDuo.cs
similarity index 100%
rename from exercises/resistor-color-duo/ResistorColorDuo.cs
rename to exercises/practice/resistor-color-duo/ResistorColorDuo.cs
diff --git a/exercises/resistor-color-duo/ResistorColorDuo.csproj b/exercises/practice/resistor-color-duo/ResistorColorDuo.csproj
similarity index 100%
rename from exercises/resistor-color-duo/ResistorColorDuo.csproj
rename to exercises/practice/resistor-color-duo/ResistorColorDuo.csproj
diff --git a/exercises/resistor-color-duo/ResistorColorDuoTests.cs b/exercises/practice/resistor-color-duo/ResistorColorDuoTests.cs
similarity index 100%
rename from exercises/resistor-color-duo/ResistorColorDuoTests.cs
rename to exercises/practice/resistor-color-duo/ResistorColorDuoTests.cs
diff --git a/exercises/resistor-color-trio/.editorconfig b/exercises/practice/resistor-color-trio/.editorconfig
similarity index 100%
rename from exercises/resistor-color-trio/.editorconfig
rename to exercises/practice/resistor-color-trio/.editorconfig
diff --git a/exercises/resistor-color-trio/.meta/tests.toml b/exercises/practice/resistor-color-trio/.meta/tests.toml
similarity index 100%
rename from exercises/resistor-color-trio/.meta/tests.toml
rename to exercises/practice/resistor-color-trio/.meta/tests.toml
diff --git a/exercises/resistor-color-trio/Example.cs b/exercises/practice/resistor-color-trio/Example.cs
similarity index 100%
rename from exercises/resistor-color-trio/Example.cs
rename to exercises/practice/resistor-color-trio/Example.cs
diff --git a/exercises/resistor-color-trio/README.md b/exercises/practice/resistor-color-trio/README.md
similarity index 100%
rename from exercises/resistor-color-trio/README.md
rename to exercises/practice/resistor-color-trio/README.md
diff --git a/exercises/resistor-color-trio/ResistorColorTrio.cs b/exercises/practice/resistor-color-trio/ResistorColorTrio.cs
similarity index 100%
rename from exercises/resistor-color-trio/ResistorColorTrio.cs
rename to exercises/practice/resistor-color-trio/ResistorColorTrio.cs
diff --git a/exercises/resistor-color-trio/ResistorColorTrio.csproj b/exercises/practice/resistor-color-trio/ResistorColorTrio.csproj
similarity index 100%
rename from exercises/resistor-color-trio/ResistorColorTrio.csproj
rename to exercises/practice/resistor-color-trio/ResistorColorTrio.csproj
diff --git a/exercises/resistor-color-trio/ResistorColorTrioTests.cs b/exercises/practice/resistor-color-trio/ResistorColorTrioTests.cs
similarity index 100%
rename from exercises/resistor-color-trio/ResistorColorTrioTests.cs
rename to exercises/practice/resistor-color-trio/ResistorColorTrioTests.cs
diff --git a/exercises/resistor-color/.editorconfig b/exercises/practice/resistor-color/.editorconfig
similarity index 100%
rename from exercises/resistor-color/.editorconfig
rename to exercises/practice/resistor-color/.editorconfig
diff --git a/exercises/resistor-color/.meta/tests.toml b/exercises/practice/resistor-color/.meta/tests.toml
similarity index 100%
rename from exercises/resistor-color/.meta/tests.toml
rename to exercises/practice/resistor-color/.meta/tests.toml
diff --git a/exercises/resistor-color/Example.cs b/exercises/practice/resistor-color/Example.cs
similarity index 100%
rename from exercises/resistor-color/Example.cs
rename to exercises/practice/resistor-color/Example.cs
diff --git a/exercises/resistor-color/README.md b/exercises/practice/resistor-color/README.md
similarity index 100%
rename from exercises/resistor-color/README.md
rename to exercises/practice/resistor-color/README.md
diff --git a/exercises/resistor-color/ResistorColor.cs b/exercises/practice/resistor-color/ResistorColor.cs
similarity index 100%
rename from exercises/resistor-color/ResistorColor.cs
rename to exercises/practice/resistor-color/ResistorColor.cs
diff --git a/exercises/resistor-color/ResistorColor.csproj b/exercises/practice/resistor-color/ResistorColor.csproj
similarity index 100%
rename from exercises/resistor-color/ResistorColor.csproj
rename to exercises/practice/resistor-color/ResistorColor.csproj
diff --git a/exercises/resistor-color/ResistorColorTests.cs b/exercises/practice/resistor-color/ResistorColorTests.cs
similarity index 100%
rename from exercises/resistor-color/ResistorColorTests.cs
rename to exercises/practice/resistor-color/ResistorColorTests.cs
diff --git a/exercises/rest-api/.editorconfig b/exercises/practice/rest-api/.editorconfig
similarity index 100%
rename from exercises/rest-api/.editorconfig
rename to exercises/practice/rest-api/.editorconfig
diff --git a/exercises/rest-api/.meta/tests.toml b/exercises/practice/rest-api/.meta/tests.toml
similarity index 100%
rename from exercises/rest-api/.meta/tests.toml
rename to exercises/practice/rest-api/.meta/tests.toml
diff --git a/exercises/rest-api/Example.cs b/exercises/practice/rest-api/Example.cs
similarity index 100%
rename from exercises/rest-api/Example.cs
rename to exercises/practice/rest-api/Example.cs
diff --git a/exercises/rest-api/README.md b/exercises/practice/rest-api/README.md
similarity index 100%
rename from exercises/rest-api/README.md
rename to exercises/practice/rest-api/README.md
diff --git a/exercises/rest-api/RestApi.cs b/exercises/practice/rest-api/RestApi.cs
similarity index 100%
rename from exercises/rest-api/RestApi.cs
rename to exercises/practice/rest-api/RestApi.cs
diff --git a/exercises/rest-api/RestApi.csproj b/exercises/practice/rest-api/RestApi.csproj
similarity index 100%
rename from exercises/rest-api/RestApi.csproj
rename to exercises/practice/rest-api/RestApi.csproj
diff --git a/exercises/rest-api/RestApiTests.cs b/exercises/practice/rest-api/RestApiTests.cs
similarity index 100%
rename from exercises/rest-api/RestApiTests.cs
rename to exercises/practice/rest-api/RestApiTests.cs
diff --git a/exercises/reverse-string/.editorconfig b/exercises/practice/reverse-string/.editorconfig
similarity index 100%
rename from exercises/reverse-string/.editorconfig
rename to exercises/practice/reverse-string/.editorconfig
diff --git a/exercises/reverse-string/.meta/tests.toml b/exercises/practice/reverse-string/.meta/tests.toml
similarity index 100%
rename from exercises/reverse-string/.meta/tests.toml
rename to exercises/practice/reverse-string/.meta/tests.toml
diff --git a/exercises/reverse-string/Example.cs b/exercises/practice/reverse-string/Example.cs
similarity index 100%
rename from exercises/reverse-string/Example.cs
rename to exercises/practice/reverse-string/Example.cs
diff --git a/exercises/reverse-string/README.md b/exercises/practice/reverse-string/README.md
similarity index 100%
rename from exercises/reverse-string/README.md
rename to exercises/practice/reverse-string/README.md
diff --git a/exercises/reverse-string/ReverseString.cs b/exercises/practice/reverse-string/ReverseString.cs
similarity index 100%
rename from exercises/reverse-string/ReverseString.cs
rename to exercises/practice/reverse-string/ReverseString.cs
diff --git a/exercises/reverse-string/ReverseString.csproj b/exercises/practice/reverse-string/ReverseString.csproj
similarity index 100%
rename from exercises/reverse-string/ReverseString.csproj
rename to exercises/practice/reverse-string/ReverseString.csproj
diff --git a/exercises/reverse-string/ReverseStringTests.cs b/exercises/practice/reverse-string/ReverseStringTests.cs
similarity index 100%
rename from exercises/reverse-string/ReverseStringTests.cs
rename to exercises/practice/reverse-string/ReverseStringTests.cs
diff --git a/exercises/rna-transcription/.editorconfig b/exercises/practice/rna-transcription/.editorconfig
similarity index 100%
rename from exercises/rna-transcription/.editorconfig
rename to exercises/practice/rna-transcription/.editorconfig
diff --git a/exercises/rna-transcription/.meta/tests.toml b/exercises/practice/rna-transcription/.meta/tests.toml
similarity index 100%
rename from exercises/rna-transcription/.meta/tests.toml
rename to exercises/practice/rna-transcription/.meta/tests.toml
diff --git a/exercises/rna-transcription/Example.cs b/exercises/practice/rna-transcription/Example.cs
similarity index 100%
rename from exercises/rna-transcription/Example.cs
rename to exercises/practice/rna-transcription/Example.cs
diff --git a/exercises/rna-transcription/README.md b/exercises/practice/rna-transcription/README.md
similarity index 100%
rename from exercises/rna-transcription/README.md
rename to exercises/practice/rna-transcription/README.md
diff --git a/exercises/rna-transcription/RnaTranscription.cs b/exercises/practice/rna-transcription/RnaTranscription.cs
similarity index 100%
rename from exercises/rna-transcription/RnaTranscription.cs
rename to exercises/practice/rna-transcription/RnaTranscription.cs
diff --git a/exercises/rna-transcription/RnaTranscription.csproj b/exercises/practice/rna-transcription/RnaTranscription.csproj
similarity index 100%
rename from exercises/rna-transcription/RnaTranscription.csproj
rename to exercises/practice/rna-transcription/RnaTranscription.csproj
diff --git a/exercises/rna-transcription/RnaTranscriptionTests.cs b/exercises/practice/rna-transcription/RnaTranscriptionTests.cs
similarity index 100%
rename from exercises/rna-transcription/RnaTranscriptionTests.cs
rename to exercises/practice/rna-transcription/RnaTranscriptionTests.cs
diff --git a/exercises/robot-name/.editorconfig b/exercises/practice/robot-name/.editorconfig
similarity index 100%
rename from exercises/robot-name/.editorconfig
rename to exercises/practice/robot-name/.editorconfig
diff --git a/exercises/robot-name/Example.cs b/exercises/practice/robot-name/Example.cs
similarity index 100%
rename from exercises/robot-name/Example.cs
rename to exercises/practice/robot-name/Example.cs
diff --git a/exercises/robot-name/README.md b/exercises/practice/robot-name/README.md
similarity index 100%
rename from exercises/robot-name/README.md
rename to exercises/practice/robot-name/README.md
diff --git a/exercises/robot-name/RobotName.cs b/exercises/practice/robot-name/RobotName.cs
similarity index 100%
rename from exercises/robot-name/RobotName.cs
rename to exercises/practice/robot-name/RobotName.cs
diff --git a/exercises/robot-name/RobotName.csproj b/exercises/practice/robot-name/RobotName.csproj
similarity index 100%
rename from exercises/robot-name/RobotName.csproj
rename to exercises/practice/robot-name/RobotName.csproj
diff --git a/exercises/robot-name/RobotNameTests.cs b/exercises/practice/robot-name/RobotNameTests.cs
similarity index 100%
rename from exercises/robot-name/RobotNameTests.cs
rename to exercises/practice/robot-name/RobotNameTests.cs
diff --git a/exercises/robot-simulator/.editorconfig b/exercises/practice/robot-simulator/.editorconfig
similarity index 100%
rename from exercises/robot-simulator/.editorconfig
rename to exercises/practice/robot-simulator/.editorconfig
diff --git a/exercises/robot-simulator/.meta/tests.toml b/exercises/practice/robot-simulator/.meta/tests.toml
similarity index 100%
rename from exercises/robot-simulator/.meta/tests.toml
rename to exercises/practice/robot-simulator/.meta/tests.toml
diff --git a/exercises/robot-simulator/Example.cs b/exercises/practice/robot-simulator/Example.cs
similarity index 100%
rename from exercises/robot-simulator/Example.cs
rename to exercises/practice/robot-simulator/Example.cs
diff --git a/exercises/robot-simulator/README.md b/exercises/practice/robot-simulator/README.md
similarity index 100%
rename from exercises/robot-simulator/README.md
rename to exercises/practice/robot-simulator/README.md
diff --git a/exercises/robot-simulator/RobotSimulator.cs b/exercises/practice/robot-simulator/RobotSimulator.cs
similarity index 100%
rename from exercises/robot-simulator/RobotSimulator.cs
rename to exercises/practice/robot-simulator/RobotSimulator.cs
diff --git a/exercises/robot-simulator/RobotSimulator.csproj b/exercises/practice/robot-simulator/RobotSimulator.csproj
similarity index 100%
rename from exercises/robot-simulator/RobotSimulator.csproj
rename to exercises/practice/robot-simulator/RobotSimulator.csproj
diff --git a/exercises/robot-simulator/RobotSimulatorTests.cs b/exercises/practice/robot-simulator/RobotSimulatorTests.cs
similarity index 100%
rename from exercises/robot-simulator/RobotSimulatorTests.cs
rename to exercises/practice/robot-simulator/RobotSimulatorTests.cs
diff --git a/exercises/roman-numerals/.editorconfig b/exercises/practice/roman-numerals/.editorconfig
similarity index 100%
rename from exercises/roman-numerals/.editorconfig
rename to exercises/practice/roman-numerals/.editorconfig
diff --git a/exercises/roman-numerals/.meta/hints.md b/exercises/practice/roman-numerals/.meta/hints.md
similarity index 100%
rename from exercises/roman-numerals/.meta/hints.md
rename to exercises/practice/roman-numerals/.meta/hints.md
diff --git a/exercises/roman-numerals/.meta/tests.toml b/exercises/practice/roman-numerals/.meta/tests.toml
similarity index 100%
rename from exercises/roman-numerals/.meta/tests.toml
rename to exercises/practice/roman-numerals/.meta/tests.toml
diff --git a/exercises/roman-numerals/Example.cs b/exercises/practice/roman-numerals/Example.cs
similarity index 100%
rename from exercises/roman-numerals/Example.cs
rename to exercises/practice/roman-numerals/Example.cs
diff --git a/exercises/roman-numerals/README.md b/exercises/practice/roman-numerals/README.md
similarity index 100%
rename from exercises/roman-numerals/README.md
rename to exercises/practice/roman-numerals/README.md
diff --git a/exercises/roman-numerals/RomanNumerals.cs b/exercises/practice/roman-numerals/RomanNumerals.cs
similarity index 100%
rename from exercises/roman-numerals/RomanNumerals.cs
rename to exercises/practice/roman-numerals/RomanNumerals.cs
diff --git a/exercises/roman-numerals/RomanNumerals.csproj b/exercises/practice/roman-numerals/RomanNumerals.csproj
similarity index 100%
rename from exercises/roman-numerals/RomanNumerals.csproj
rename to exercises/practice/roman-numerals/RomanNumerals.csproj
diff --git a/exercises/roman-numerals/RomanNumeralsTests.cs b/exercises/practice/roman-numerals/RomanNumeralsTests.cs
similarity index 100%
rename from exercises/roman-numerals/RomanNumeralsTests.cs
rename to exercises/practice/roman-numerals/RomanNumeralsTests.cs
diff --git a/exercises/rotational-cipher/.editorconfig b/exercises/practice/rotational-cipher/.editorconfig
similarity index 100%
rename from exercises/rotational-cipher/.editorconfig
rename to exercises/practice/rotational-cipher/.editorconfig
diff --git a/exercises/rotational-cipher/.meta/tests.toml b/exercises/practice/rotational-cipher/.meta/tests.toml
similarity index 100%
rename from exercises/rotational-cipher/.meta/tests.toml
rename to exercises/practice/rotational-cipher/.meta/tests.toml
diff --git a/exercises/rotational-cipher/Example.cs b/exercises/practice/rotational-cipher/Example.cs
similarity index 100%
rename from exercises/rotational-cipher/Example.cs
rename to exercises/practice/rotational-cipher/Example.cs
diff --git a/exercises/rotational-cipher/README.md b/exercises/practice/rotational-cipher/README.md
similarity index 100%
rename from exercises/rotational-cipher/README.md
rename to exercises/practice/rotational-cipher/README.md
diff --git a/exercises/rotational-cipher/RotationalCipher.cs b/exercises/practice/rotational-cipher/RotationalCipher.cs
similarity index 100%
rename from exercises/rotational-cipher/RotationalCipher.cs
rename to exercises/practice/rotational-cipher/RotationalCipher.cs
diff --git a/exercises/rotational-cipher/RotationalCipher.csproj b/exercises/practice/rotational-cipher/RotationalCipher.csproj
similarity index 100%
rename from exercises/rotational-cipher/RotationalCipher.csproj
rename to exercises/practice/rotational-cipher/RotationalCipher.csproj
diff --git a/exercises/rotational-cipher/RotationalCipherTests.cs b/exercises/practice/rotational-cipher/RotationalCipherTests.cs
similarity index 100%
rename from exercises/rotational-cipher/RotationalCipherTests.cs
rename to exercises/practice/rotational-cipher/RotationalCipherTests.cs
diff --git a/exercises/run-length-encoding/.editorconfig b/exercises/practice/run-length-encoding/.editorconfig
similarity index 100%
rename from exercises/run-length-encoding/.editorconfig
rename to exercises/practice/run-length-encoding/.editorconfig
diff --git a/exercises/run-length-encoding/.meta/tests.toml b/exercises/practice/run-length-encoding/.meta/tests.toml
similarity index 100%
rename from exercises/run-length-encoding/.meta/tests.toml
rename to exercises/practice/run-length-encoding/.meta/tests.toml
diff --git a/exercises/run-length-encoding/Example.cs b/exercises/practice/run-length-encoding/Example.cs
similarity index 100%
rename from exercises/run-length-encoding/Example.cs
rename to exercises/practice/run-length-encoding/Example.cs
diff --git a/exercises/run-length-encoding/README.md b/exercises/practice/run-length-encoding/README.md
similarity index 100%
rename from exercises/run-length-encoding/README.md
rename to exercises/practice/run-length-encoding/README.md
diff --git a/exercises/run-length-encoding/RunLengthEncoding.cs b/exercises/practice/run-length-encoding/RunLengthEncoding.cs
similarity index 100%
rename from exercises/run-length-encoding/RunLengthEncoding.cs
rename to exercises/practice/run-length-encoding/RunLengthEncoding.cs
diff --git a/exercises/run-length-encoding/RunLengthEncoding.csproj b/exercises/practice/run-length-encoding/RunLengthEncoding.csproj
similarity index 100%
rename from exercises/run-length-encoding/RunLengthEncoding.csproj
rename to exercises/practice/run-length-encoding/RunLengthEncoding.csproj
diff --git a/exercises/run-length-encoding/RunLengthEncodingTests.cs b/exercises/practice/run-length-encoding/RunLengthEncodingTests.cs
similarity index 100%
rename from exercises/run-length-encoding/RunLengthEncodingTests.cs
rename to exercises/practice/run-length-encoding/RunLengthEncodingTests.cs
diff --git a/exercises/saddle-points/.editorconfig b/exercises/practice/saddle-points/.editorconfig
similarity index 100%
rename from exercises/saddle-points/.editorconfig
rename to exercises/practice/saddle-points/.editorconfig
diff --git a/exercises/saddle-points/.meta/hints.md b/exercises/practice/saddle-points/.meta/hints.md
similarity index 100%
rename from exercises/saddle-points/.meta/hints.md
rename to exercises/practice/saddle-points/.meta/hints.md
diff --git a/exercises/saddle-points/.meta/tests.toml b/exercises/practice/saddle-points/.meta/tests.toml
similarity index 100%
rename from exercises/saddle-points/.meta/tests.toml
rename to exercises/practice/saddle-points/.meta/tests.toml
diff --git a/exercises/saddle-points/Example.cs b/exercises/practice/saddle-points/Example.cs
similarity index 100%
rename from exercises/saddle-points/Example.cs
rename to exercises/practice/saddle-points/Example.cs
diff --git a/exercises/saddle-points/README.md b/exercises/practice/saddle-points/README.md
similarity index 100%
rename from exercises/saddle-points/README.md
rename to exercises/practice/saddle-points/README.md
diff --git a/exercises/saddle-points/SaddlePoints.cs b/exercises/practice/saddle-points/SaddlePoints.cs
similarity index 100%
rename from exercises/saddle-points/SaddlePoints.cs
rename to exercises/practice/saddle-points/SaddlePoints.cs
diff --git a/exercises/saddle-points/SaddlePoints.csproj b/exercises/practice/saddle-points/SaddlePoints.csproj
similarity index 100%
rename from exercises/saddle-points/SaddlePoints.csproj
rename to exercises/practice/saddle-points/SaddlePoints.csproj
diff --git a/exercises/saddle-points/SaddlePointsTests.cs b/exercises/practice/saddle-points/SaddlePointsTests.cs
similarity index 100%
rename from exercises/saddle-points/SaddlePointsTests.cs
rename to exercises/practice/saddle-points/SaddlePointsTests.cs
diff --git a/exercises/say/.editorconfig b/exercises/practice/say/.editorconfig
similarity index 100%
rename from exercises/say/.editorconfig
rename to exercises/practice/say/.editorconfig
diff --git a/exercises/say/.meta/tests.toml b/exercises/practice/say/.meta/tests.toml
similarity index 100%
rename from exercises/say/.meta/tests.toml
rename to exercises/practice/say/.meta/tests.toml
diff --git a/exercises/say/Example.cs b/exercises/practice/say/Example.cs
similarity index 100%
rename from exercises/say/Example.cs
rename to exercises/practice/say/Example.cs
diff --git a/exercises/say/README.md b/exercises/practice/say/README.md
similarity index 100%
rename from exercises/say/README.md
rename to exercises/practice/say/README.md
diff --git a/exercises/say/Say.cs b/exercises/practice/say/Say.cs
similarity index 100%
rename from exercises/say/Say.cs
rename to exercises/practice/say/Say.cs
diff --git a/exercises/say/Say.csproj b/exercises/practice/say/Say.csproj
similarity index 100%
rename from exercises/say/Say.csproj
rename to exercises/practice/say/Say.csproj
diff --git a/exercises/say/SayTests.cs b/exercises/practice/say/SayTests.cs
similarity index 100%
rename from exercises/say/SayTests.cs
rename to exercises/practice/say/SayTests.cs
diff --git a/exercises/scale-generator/.editorconfig b/exercises/practice/scale-generator/.editorconfig
similarity index 100%
rename from exercises/scale-generator/.editorconfig
rename to exercises/practice/scale-generator/.editorconfig
diff --git a/exercises/scale-generator/.meta/tests.toml b/exercises/practice/scale-generator/.meta/tests.toml
similarity index 100%
rename from exercises/scale-generator/.meta/tests.toml
rename to exercises/practice/scale-generator/.meta/tests.toml
diff --git a/exercises/scale-generator/Example.cs b/exercises/practice/scale-generator/Example.cs
similarity index 100%
rename from exercises/scale-generator/Example.cs
rename to exercises/practice/scale-generator/Example.cs
diff --git a/exercises/scale-generator/README.md b/exercises/practice/scale-generator/README.md
similarity index 100%
rename from exercises/scale-generator/README.md
rename to exercises/practice/scale-generator/README.md
diff --git a/exercises/scale-generator/ScaleGenerator.cs b/exercises/practice/scale-generator/ScaleGenerator.cs
similarity index 100%
rename from exercises/scale-generator/ScaleGenerator.cs
rename to exercises/practice/scale-generator/ScaleGenerator.cs
diff --git a/exercises/scale-generator/ScaleGenerator.csproj b/exercises/practice/scale-generator/ScaleGenerator.csproj
similarity index 100%
rename from exercises/scale-generator/ScaleGenerator.csproj
rename to exercises/practice/scale-generator/ScaleGenerator.csproj
diff --git a/exercises/scale-generator/ScaleGeneratorTests.cs b/exercises/practice/scale-generator/ScaleGeneratorTests.cs
similarity index 100%
rename from exercises/scale-generator/ScaleGeneratorTests.cs
rename to exercises/practice/scale-generator/ScaleGeneratorTests.cs
diff --git a/exercises/scrabble-score/.editorconfig b/exercises/practice/scrabble-score/.editorconfig
similarity index 100%
rename from exercises/scrabble-score/.editorconfig
rename to exercises/practice/scrabble-score/.editorconfig
diff --git a/exercises/scrabble-score/.meta/tests.toml b/exercises/practice/scrabble-score/.meta/tests.toml
similarity index 100%
rename from exercises/scrabble-score/.meta/tests.toml
rename to exercises/practice/scrabble-score/.meta/tests.toml
diff --git a/exercises/scrabble-score/Example.cs b/exercises/practice/scrabble-score/Example.cs
similarity index 100%
rename from exercises/scrabble-score/Example.cs
rename to exercises/practice/scrabble-score/Example.cs
diff --git a/exercises/scrabble-score/README.md b/exercises/practice/scrabble-score/README.md
similarity index 100%
rename from exercises/scrabble-score/README.md
rename to exercises/practice/scrabble-score/README.md
diff --git a/exercises/scrabble-score/ScrabbleScore.cs b/exercises/practice/scrabble-score/ScrabbleScore.cs
similarity index 100%
rename from exercises/scrabble-score/ScrabbleScore.cs
rename to exercises/practice/scrabble-score/ScrabbleScore.cs
diff --git a/exercises/scrabble-score/ScrabbleScore.csproj b/exercises/practice/scrabble-score/ScrabbleScore.csproj
similarity index 100%
rename from exercises/scrabble-score/ScrabbleScore.csproj
rename to exercises/practice/scrabble-score/ScrabbleScore.csproj
diff --git a/exercises/scrabble-score/ScrabbleScoreTests.cs b/exercises/practice/scrabble-score/ScrabbleScoreTests.cs
similarity index 100%
rename from exercises/scrabble-score/ScrabbleScoreTests.cs
rename to exercises/practice/scrabble-score/ScrabbleScoreTests.cs
diff --git a/exercises/secret-handshake/.editorconfig b/exercises/practice/secret-handshake/.editorconfig
similarity index 100%
rename from exercises/secret-handshake/.editorconfig
rename to exercises/practice/secret-handshake/.editorconfig
diff --git a/exercises/secret-handshake/.meta/tests.toml b/exercises/practice/secret-handshake/.meta/tests.toml
similarity index 100%
rename from exercises/secret-handshake/.meta/tests.toml
rename to exercises/practice/secret-handshake/.meta/tests.toml
diff --git a/exercises/secret-handshake/Example.cs b/exercises/practice/secret-handshake/Example.cs
similarity index 100%
rename from exercises/secret-handshake/Example.cs
rename to exercises/practice/secret-handshake/Example.cs
diff --git a/exercises/secret-handshake/README.md b/exercises/practice/secret-handshake/README.md
similarity index 100%
rename from exercises/secret-handshake/README.md
rename to exercises/practice/secret-handshake/README.md
diff --git a/exercises/secret-handshake/SecretHandshake.cs b/exercises/practice/secret-handshake/SecretHandshake.cs
similarity index 100%
rename from exercises/secret-handshake/SecretHandshake.cs
rename to exercises/practice/secret-handshake/SecretHandshake.cs
diff --git a/exercises/secret-handshake/SecretHandshake.csproj b/exercises/practice/secret-handshake/SecretHandshake.csproj
similarity index 100%
rename from exercises/secret-handshake/SecretHandshake.csproj
rename to exercises/practice/secret-handshake/SecretHandshake.csproj
diff --git a/exercises/secret-handshake/SecretHandshakeTests.cs b/exercises/practice/secret-handshake/SecretHandshakeTests.cs
similarity index 100%
rename from exercises/secret-handshake/SecretHandshakeTests.cs
rename to exercises/practice/secret-handshake/SecretHandshakeTests.cs
diff --git a/exercises/series/.editorconfig b/exercises/practice/series/.editorconfig
similarity index 100%
rename from exercises/series/.editorconfig
rename to exercises/practice/series/.editorconfig
diff --git a/exercises/series/.meta/tests.toml b/exercises/practice/series/.meta/tests.toml
similarity index 100%
rename from exercises/series/.meta/tests.toml
rename to exercises/practice/series/.meta/tests.toml
diff --git a/exercises/series/Example.cs b/exercises/practice/series/Example.cs
similarity index 100%
rename from exercises/series/Example.cs
rename to exercises/practice/series/Example.cs
diff --git a/exercises/series/README.md b/exercises/practice/series/README.md
similarity index 100%
rename from exercises/series/README.md
rename to exercises/practice/series/README.md
diff --git a/exercises/series/Series.cs b/exercises/practice/series/Series.cs
similarity index 100%
rename from exercises/series/Series.cs
rename to exercises/practice/series/Series.cs
diff --git a/exercises/series/Series.csproj b/exercises/practice/series/Series.csproj
similarity index 100%
rename from exercises/series/Series.csproj
rename to exercises/practice/series/Series.csproj
diff --git a/exercises/series/SeriesTests.cs b/exercises/practice/series/SeriesTests.cs
similarity index 100%
rename from exercises/series/SeriesTests.cs
rename to exercises/practice/series/SeriesTests.cs
diff --git a/exercises/sgf-parsing/.editorconfig b/exercises/practice/sgf-parsing/.editorconfig
similarity index 100%
rename from exercises/sgf-parsing/.editorconfig
rename to exercises/practice/sgf-parsing/.editorconfig
diff --git a/exercises/sgf-parsing/.meta/hints.md b/exercises/practice/sgf-parsing/.meta/hints.md
similarity index 100%
rename from exercises/sgf-parsing/.meta/hints.md
rename to exercises/practice/sgf-parsing/.meta/hints.md
diff --git a/exercises/sgf-parsing/.meta/tests.toml b/exercises/practice/sgf-parsing/.meta/tests.toml
similarity index 100%
rename from exercises/sgf-parsing/.meta/tests.toml
rename to exercises/practice/sgf-parsing/.meta/tests.toml
diff --git a/exercises/sgf-parsing/Example.cs b/exercises/practice/sgf-parsing/Example.cs
similarity index 100%
rename from exercises/sgf-parsing/Example.cs
rename to exercises/practice/sgf-parsing/Example.cs
diff --git a/exercises/sgf-parsing/README.md b/exercises/practice/sgf-parsing/README.md
similarity index 100%
rename from exercises/sgf-parsing/README.md
rename to exercises/practice/sgf-parsing/README.md
diff --git a/exercises/sgf-parsing/SgfParsing.cs b/exercises/practice/sgf-parsing/SgfParsing.cs
similarity index 100%
rename from exercises/sgf-parsing/SgfParsing.cs
rename to exercises/practice/sgf-parsing/SgfParsing.cs
diff --git a/exercises/sgf-parsing/SgfParsing.csproj b/exercises/practice/sgf-parsing/SgfParsing.csproj
similarity index 100%
rename from exercises/sgf-parsing/SgfParsing.csproj
rename to exercises/practice/sgf-parsing/SgfParsing.csproj
diff --git a/exercises/sgf-parsing/SgfParsingTests.cs b/exercises/practice/sgf-parsing/SgfParsingTests.cs
similarity index 100%
rename from exercises/sgf-parsing/SgfParsingTests.cs
rename to exercises/practice/sgf-parsing/SgfParsingTests.cs
diff --git a/exercises/sieve/.editorconfig b/exercises/practice/sieve/.editorconfig
similarity index 100%
rename from exercises/sieve/.editorconfig
rename to exercises/practice/sieve/.editorconfig
diff --git a/exercises/sieve/.meta/tests.toml b/exercises/practice/sieve/.meta/tests.toml
similarity index 100%
rename from exercises/sieve/.meta/tests.toml
rename to exercises/practice/sieve/.meta/tests.toml
diff --git a/exercises/sieve/Example.cs b/exercises/practice/sieve/Example.cs
similarity index 100%
rename from exercises/sieve/Example.cs
rename to exercises/practice/sieve/Example.cs
diff --git a/exercises/sieve/README.md b/exercises/practice/sieve/README.md
similarity index 100%
rename from exercises/sieve/README.md
rename to exercises/practice/sieve/README.md
diff --git a/exercises/sieve/Sieve.cs b/exercises/practice/sieve/Sieve.cs
similarity index 100%
rename from exercises/sieve/Sieve.cs
rename to exercises/practice/sieve/Sieve.cs
diff --git a/exercises/sieve/Sieve.csproj b/exercises/practice/sieve/Sieve.csproj
similarity index 100%
rename from exercises/sieve/Sieve.csproj
rename to exercises/practice/sieve/Sieve.csproj
diff --git a/exercises/sieve/SieveTests.cs b/exercises/practice/sieve/SieveTests.cs
similarity index 100%
rename from exercises/sieve/SieveTests.cs
rename to exercises/practice/sieve/SieveTests.cs
diff --git a/exercises/simple-cipher/.editorconfig b/exercises/practice/simple-cipher/.editorconfig
similarity index 100%
rename from exercises/simple-cipher/.editorconfig
rename to exercises/practice/simple-cipher/.editorconfig
diff --git a/exercises/simple-cipher/.meta/tests.toml b/exercises/practice/simple-cipher/.meta/tests.toml
similarity index 100%
rename from exercises/simple-cipher/.meta/tests.toml
rename to exercises/practice/simple-cipher/.meta/tests.toml
diff --git a/exercises/simple-cipher/Example.cs b/exercises/practice/simple-cipher/Example.cs
similarity index 100%
rename from exercises/simple-cipher/Example.cs
rename to exercises/practice/simple-cipher/Example.cs
diff --git a/exercises/simple-cipher/README.md b/exercises/practice/simple-cipher/README.md
similarity index 100%
rename from exercises/simple-cipher/README.md
rename to exercises/practice/simple-cipher/README.md
diff --git a/exercises/simple-cipher/SimpleCipher.cs b/exercises/practice/simple-cipher/SimpleCipher.cs
similarity index 100%
rename from exercises/simple-cipher/SimpleCipher.cs
rename to exercises/practice/simple-cipher/SimpleCipher.cs
diff --git a/exercises/simple-cipher/SimpleCipher.csproj b/exercises/practice/simple-cipher/SimpleCipher.csproj
similarity index 100%
rename from exercises/simple-cipher/SimpleCipher.csproj
rename to exercises/practice/simple-cipher/SimpleCipher.csproj
diff --git a/exercises/simple-cipher/SimpleCipherTests.cs b/exercises/practice/simple-cipher/SimpleCipherTests.cs
similarity index 100%
rename from exercises/simple-cipher/SimpleCipherTests.cs
rename to exercises/practice/simple-cipher/SimpleCipherTests.cs
diff --git a/exercises/simple-linked-list/.editorconfig b/exercises/practice/simple-linked-list/.editorconfig
similarity index 100%
rename from exercises/simple-linked-list/.editorconfig
rename to exercises/practice/simple-linked-list/.editorconfig
diff --git a/exercises/simple-linked-list/.meta/hints.md b/exercises/practice/simple-linked-list/.meta/hints.md
similarity index 100%
rename from exercises/simple-linked-list/.meta/hints.md
rename to exercises/practice/simple-linked-list/.meta/hints.md
diff --git a/exercises/simple-linked-list/Example.cs b/exercises/practice/simple-linked-list/Example.cs
similarity index 100%
rename from exercises/simple-linked-list/Example.cs
rename to exercises/practice/simple-linked-list/Example.cs
diff --git a/exercises/simple-linked-list/README.md b/exercises/practice/simple-linked-list/README.md
similarity index 100%
rename from exercises/simple-linked-list/README.md
rename to exercises/practice/simple-linked-list/README.md
diff --git a/exercises/simple-linked-list/SimpleLinkedList.cs b/exercises/practice/simple-linked-list/SimpleLinkedList.cs
similarity index 100%
rename from exercises/simple-linked-list/SimpleLinkedList.cs
rename to exercises/practice/simple-linked-list/SimpleLinkedList.cs
diff --git a/exercises/simple-linked-list/SimpleLinkedList.csproj b/exercises/practice/simple-linked-list/SimpleLinkedList.csproj
similarity index 100%
rename from exercises/simple-linked-list/SimpleLinkedList.csproj
rename to exercises/practice/simple-linked-list/SimpleLinkedList.csproj
diff --git a/exercises/simple-linked-list/SimpleLinkedListTests.cs b/exercises/practice/simple-linked-list/SimpleLinkedListTests.cs
similarity index 100%
rename from exercises/simple-linked-list/SimpleLinkedListTests.cs
rename to exercises/practice/simple-linked-list/SimpleLinkedListTests.cs
diff --git a/exercises/space-age/.editorconfig b/exercises/practice/space-age/.editorconfig
similarity index 100%
rename from exercises/space-age/.editorconfig
rename to exercises/practice/space-age/.editorconfig
diff --git a/exercises/space-age/.meta/tests.toml b/exercises/practice/space-age/.meta/tests.toml
similarity index 100%
rename from exercises/space-age/.meta/tests.toml
rename to exercises/practice/space-age/.meta/tests.toml
diff --git a/exercises/space-age/Example.cs b/exercises/practice/space-age/Example.cs
similarity index 100%
rename from exercises/space-age/Example.cs
rename to exercises/practice/space-age/Example.cs
diff --git a/exercises/space-age/README.md b/exercises/practice/space-age/README.md
similarity index 100%
rename from exercises/space-age/README.md
rename to exercises/practice/space-age/README.md
diff --git a/exercises/space-age/SpaceAge.cs b/exercises/practice/space-age/SpaceAge.cs
similarity index 100%
rename from exercises/space-age/SpaceAge.cs
rename to exercises/practice/space-age/SpaceAge.cs
diff --git a/exercises/space-age/SpaceAge.csproj b/exercises/practice/space-age/SpaceAge.csproj
similarity index 100%
rename from exercises/space-age/SpaceAge.csproj
rename to exercises/practice/space-age/SpaceAge.csproj
diff --git a/exercises/space-age/SpaceAgeTests.cs b/exercises/practice/space-age/SpaceAgeTests.cs
similarity index 100%
rename from exercises/space-age/SpaceAgeTests.cs
rename to exercises/practice/space-age/SpaceAgeTests.cs
diff --git a/exercises/spiral-matrix/.editorconfig b/exercises/practice/spiral-matrix/.editorconfig
similarity index 100%
rename from exercises/spiral-matrix/.editorconfig
rename to exercises/practice/spiral-matrix/.editorconfig
diff --git a/exercises/spiral-matrix/.meta/tests.toml b/exercises/practice/spiral-matrix/.meta/tests.toml
similarity index 100%
rename from exercises/spiral-matrix/.meta/tests.toml
rename to exercises/practice/spiral-matrix/.meta/tests.toml
diff --git a/exercises/spiral-matrix/Example.cs b/exercises/practice/spiral-matrix/Example.cs
similarity index 100%
rename from exercises/spiral-matrix/Example.cs
rename to exercises/practice/spiral-matrix/Example.cs
diff --git a/exercises/spiral-matrix/README.md b/exercises/practice/spiral-matrix/README.md
similarity index 100%
rename from exercises/spiral-matrix/README.md
rename to exercises/practice/spiral-matrix/README.md
diff --git a/exercises/spiral-matrix/SpiralMatrix.cs b/exercises/practice/spiral-matrix/SpiralMatrix.cs
similarity index 100%
rename from exercises/spiral-matrix/SpiralMatrix.cs
rename to exercises/practice/spiral-matrix/SpiralMatrix.cs
diff --git a/exercises/spiral-matrix/SpiralMatrix.csproj b/exercises/practice/spiral-matrix/SpiralMatrix.csproj
similarity index 100%
rename from exercises/spiral-matrix/SpiralMatrix.csproj
rename to exercises/practice/spiral-matrix/SpiralMatrix.csproj
diff --git a/exercises/spiral-matrix/SpiralMatrixTests.cs b/exercises/practice/spiral-matrix/SpiralMatrixTests.cs
similarity index 100%
rename from exercises/spiral-matrix/SpiralMatrixTests.cs
rename to exercises/practice/spiral-matrix/SpiralMatrixTests.cs
diff --git a/exercises/strain/.editorconfig b/exercises/practice/strain/.editorconfig
similarity index 100%
rename from exercises/strain/.editorconfig
rename to exercises/practice/strain/.editorconfig
diff --git a/exercises/strain/Example.cs b/exercises/practice/strain/Example.cs
similarity index 100%
rename from exercises/strain/Example.cs
rename to exercises/practice/strain/Example.cs
diff --git a/exercises/strain/README.md b/exercises/practice/strain/README.md
similarity index 100%
rename from exercises/strain/README.md
rename to exercises/practice/strain/README.md
diff --git a/exercises/strain/Strain.cs b/exercises/practice/strain/Strain.cs
similarity index 100%
rename from exercises/strain/Strain.cs
rename to exercises/practice/strain/Strain.cs
diff --git a/exercises/strain/Strain.csproj b/exercises/practice/strain/Strain.csproj
similarity index 100%
rename from exercises/strain/Strain.csproj
rename to exercises/practice/strain/Strain.csproj
diff --git a/exercises/strain/StrainTests.cs b/exercises/practice/strain/StrainTests.cs
similarity index 100%
rename from exercises/strain/StrainTests.cs
rename to exercises/practice/strain/StrainTests.cs
diff --git a/exercises/sublist/.editorconfig b/exercises/practice/sublist/.editorconfig
similarity index 100%
rename from exercises/sublist/.editorconfig
rename to exercises/practice/sublist/.editorconfig
diff --git a/exercises/sublist/.meta/hints.md b/exercises/practice/sublist/.meta/hints.md
similarity index 100%
rename from exercises/sublist/.meta/hints.md
rename to exercises/practice/sublist/.meta/hints.md
diff --git a/exercises/sublist/.meta/tests.toml b/exercises/practice/sublist/.meta/tests.toml
similarity index 100%
rename from exercises/sublist/.meta/tests.toml
rename to exercises/practice/sublist/.meta/tests.toml
diff --git a/exercises/sublist/Example.cs b/exercises/practice/sublist/Example.cs
similarity index 100%
rename from exercises/sublist/Example.cs
rename to exercises/practice/sublist/Example.cs
diff --git a/exercises/sublist/README.md b/exercises/practice/sublist/README.md
similarity index 100%
rename from exercises/sublist/README.md
rename to exercises/practice/sublist/README.md
diff --git a/exercises/sublist/Sublist.cs b/exercises/practice/sublist/Sublist.cs
similarity index 100%
rename from exercises/sublist/Sublist.cs
rename to exercises/practice/sublist/Sublist.cs
diff --git a/exercises/sublist/Sublist.csproj b/exercises/practice/sublist/Sublist.csproj
similarity index 100%
rename from exercises/sublist/Sublist.csproj
rename to exercises/practice/sublist/Sublist.csproj
diff --git a/exercises/sublist/SublistTests.cs b/exercises/practice/sublist/SublistTests.cs
similarity index 100%
rename from exercises/sublist/SublistTests.cs
rename to exercises/practice/sublist/SublistTests.cs
diff --git a/exercises/sum-of-multiples/.editorconfig b/exercises/practice/sum-of-multiples/.editorconfig
similarity index 100%
rename from exercises/sum-of-multiples/.editorconfig
rename to exercises/practice/sum-of-multiples/.editorconfig
diff --git a/exercises/sum-of-multiples/.meta/hints.md b/exercises/practice/sum-of-multiples/.meta/hints.md
similarity index 100%
rename from exercises/sum-of-multiples/.meta/hints.md
rename to exercises/practice/sum-of-multiples/.meta/hints.md
diff --git a/exercises/sum-of-multiples/.meta/tests.toml b/exercises/practice/sum-of-multiples/.meta/tests.toml
similarity index 100%
rename from exercises/sum-of-multiples/.meta/tests.toml
rename to exercises/practice/sum-of-multiples/.meta/tests.toml
diff --git a/exercises/sum-of-multiples/Example.cs b/exercises/practice/sum-of-multiples/Example.cs
similarity index 100%
rename from exercises/sum-of-multiples/Example.cs
rename to exercises/practice/sum-of-multiples/Example.cs
diff --git a/exercises/sum-of-multiples/README.md b/exercises/practice/sum-of-multiples/README.md
similarity index 100%
rename from exercises/sum-of-multiples/README.md
rename to exercises/practice/sum-of-multiples/README.md
diff --git a/exercises/sum-of-multiples/SumOfMultiples.cs b/exercises/practice/sum-of-multiples/SumOfMultiples.cs
similarity index 100%
rename from exercises/sum-of-multiples/SumOfMultiples.cs
rename to exercises/practice/sum-of-multiples/SumOfMultiples.cs
diff --git a/exercises/sum-of-multiples/SumOfMultiples.csproj b/exercises/practice/sum-of-multiples/SumOfMultiples.csproj
similarity index 100%
rename from exercises/sum-of-multiples/SumOfMultiples.csproj
rename to exercises/practice/sum-of-multiples/SumOfMultiples.csproj
diff --git a/exercises/sum-of-multiples/SumOfMultiplesTests.cs b/exercises/practice/sum-of-multiples/SumOfMultiplesTests.cs
similarity index 100%
rename from exercises/sum-of-multiples/SumOfMultiplesTests.cs
rename to exercises/practice/sum-of-multiples/SumOfMultiplesTests.cs
diff --git a/exercises/tournament/.editorconfig b/exercises/practice/tournament/.editorconfig
similarity index 100%
rename from exercises/tournament/.editorconfig
rename to exercises/practice/tournament/.editorconfig
diff --git a/exercises/tournament/.meta/tests.toml b/exercises/practice/tournament/.meta/tests.toml
similarity index 100%
rename from exercises/tournament/.meta/tests.toml
rename to exercises/practice/tournament/.meta/tests.toml
diff --git a/exercises/tournament/Example.cs b/exercises/practice/tournament/Example.cs
similarity index 100%
rename from exercises/tournament/Example.cs
rename to exercises/practice/tournament/Example.cs
diff --git a/exercises/tournament/README.md b/exercises/practice/tournament/README.md
similarity index 100%
rename from exercises/tournament/README.md
rename to exercises/practice/tournament/README.md
diff --git a/exercises/tournament/Tournament.cs b/exercises/practice/tournament/Tournament.cs
similarity index 100%
rename from exercises/tournament/Tournament.cs
rename to exercises/practice/tournament/Tournament.cs
diff --git a/exercises/tournament/Tournament.csproj b/exercises/practice/tournament/Tournament.csproj
similarity index 100%
rename from exercises/tournament/Tournament.csproj
rename to exercises/practice/tournament/Tournament.csproj
diff --git a/exercises/tournament/TournamentTests.cs b/exercises/practice/tournament/TournamentTests.cs
similarity index 100%
rename from exercises/tournament/TournamentTests.cs
rename to exercises/practice/tournament/TournamentTests.cs
diff --git a/exercises/transpose/.editorconfig b/exercises/practice/transpose/.editorconfig
similarity index 100%
rename from exercises/transpose/.editorconfig
rename to exercises/practice/transpose/.editorconfig
diff --git a/exercises/transpose/.meta/tests.toml b/exercises/practice/transpose/.meta/tests.toml
similarity index 100%
rename from exercises/transpose/.meta/tests.toml
rename to exercises/practice/transpose/.meta/tests.toml
diff --git a/exercises/transpose/Example.cs b/exercises/practice/transpose/Example.cs
similarity index 100%
rename from exercises/transpose/Example.cs
rename to exercises/practice/transpose/Example.cs
diff --git a/exercises/transpose/README.md b/exercises/practice/transpose/README.md
similarity index 100%
rename from exercises/transpose/README.md
rename to exercises/practice/transpose/README.md
diff --git a/exercises/transpose/Transpose.cs b/exercises/practice/transpose/Transpose.cs
similarity index 100%
rename from exercises/transpose/Transpose.cs
rename to exercises/practice/transpose/Transpose.cs
diff --git a/exercises/transpose/Transpose.csproj b/exercises/practice/transpose/Transpose.csproj
similarity index 100%
rename from exercises/transpose/Transpose.csproj
rename to exercises/practice/transpose/Transpose.csproj
diff --git a/exercises/transpose/TransposeTests.cs b/exercises/practice/transpose/TransposeTests.cs
similarity index 100%
rename from exercises/transpose/TransposeTests.cs
rename to exercises/practice/transpose/TransposeTests.cs
diff --git a/exercises/tree-building/.editorconfig b/exercises/practice/tree-building/.editorconfig
similarity index 100%
rename from exercises/tree-building/.editorconfig
rename to exercises/practice/tree-building/.editorconfig
diff --git a/exercises/tree-building/Example.cs b/exercises/practice/tree-building/Example.cs
similarity index 100%
rename from exercises/tree-building/Example.cs
rename to exercises/practice/tree-building/Example.cs
diff --git a/exercises/tree-building/README.md b/exercises/practice/tree-building/README.md
similarity index 100%
rename from exercises/tree-building/README.md
rename to exercises/practice/tree-building/README.md
diff --git a/exercises/tree-building/TreeBuilding.cs b/exercises/practice/tree-building/TreeBuilding.cs
similarity index 100%
rename from exercises/tree-building/TreeBuilding.cs
rename to exercises/practice/tree-building/TreeBuilding.cs
diff --git a/exercises/tree-building/TreeBuilding.csproj b/exercises/practice/tree-building/TreeBuilding.csproj
similarity index 100%
rename from exercises/tree-building/TreeBuilding.csproj
rename to exercises/practice/tree-building/TreeBuilding.csproj
diff --git a/exercises/tree-building/TreeBuildingTests.cs b/exercises/practice/tree-building/TreeBuildingTests.cs
similarity index 100%
rename from exercises/tree-building/TreeBuildingTests.cs
rename to exercises/practice/tree-building/TreeBuildingTests.cs
diff --git a/exercises/triangle/.editorconfig b/exercises/practice/triangle/.editorconfig
similarity index 100%
rename from exercises/triangle/.editorconfig
rename to exercises/practice/triangle/.editorconfig
diff --git a/exercises/triangle/.meta/tests.toml b/exercises/practice/triangle/.meta/tests.toml
similarity index 100%
rename from exercises/triangle/.meta/tests.toml
rename to exercises/practice/triangle/.meta/tests.toml
diff --git a/exercises/triangle/Example.cs b/exercises/practice/triangle/Example.cs
similarity index 100%
rename from exercises/triangle/Example.cs
rename to exercises/practice/triangle/Example.cs
diff --git a/exercises/triangle/README.md b/exercises/practice/triangle/README.md
similarity index 100%
rename from exercises/triangle/README.md
rename to exercises/practice/triangle/README.md
diff --git a/exercises/triangle/Triangle.cs b/exercises/practice/triangle/Triangle.cs
similarity index 100%
rename from exercises/triangle/Triangle.cs
rename to exercises/practice/triangle/Triangle.cs
diff --git a/exercises/triangle/Triangle.csproj b/exercises/practice/triangle/Triangle.csproj
similarity index 100%
rename from exercises/triangle/Triangle.csproj
rename to exercises/practice/triangle/Triangle.csproj
diff --git a/exercises/triangle/TriangleTests.cs b/exercises/practice/triangle/TriangleTests.cs
similarity index 100%
rename from exercises/triangle/TriangleTests.cs
rename to exercises/practice/triangle/TriangleTests.cs
diff --git a/exercises/trinary/.editorconfig b/exercises/practice/trinary/.editorconfig
similarity index 100%
rename from exercises/trinary/.editorconfig
rename to exercises/practice/trinary/.editorconfig
diff --git a/exercises/trinary/.meta/tests.toml b/exercises/practice/trinary/.meta/tests.toml
similarity index 100%
rename from exercises/trinary/.meta/tests.toml
rename to exercises/practice/trinary/.meta/tests.toml
diff --git a/exercises/trinary/Example.cs b/exercises/practice/trinary/Example.cs
similarity index 100%
rename from exercises/trinary/Example.cs
rename to exercises/practice/trinary/Example.cs
diff --git a/exercises/trinary/README.md b/exercises/practice/trinary/README.md
similarity index 100%
rename from exercises/trinary/README.md
rename to exercises/practice/trinary/README.md
diff --git a/exercises/trinary/Trinary.cs b/exercises/practice/trinary/Trinary.cs
similarity index 100%
rename from exercises/trinary/Trinary.cs
rename to exercises/practice/trinary/Trinary.cs
diff --git a/exercises/trinary/Trinary.csproj b/exercises/practice/trinary/Trinary.csproj
similarity index 100%
rename from exercises/trinary/Trinary.csproj
rename to exercises/practice/trinary/Trinary.csproj
diff --git a/exercises/trinary/TrinaryTests.cs b/exercises/practice/trinary/TrinaryTests.cs
similarity index 100%
rename from exercises/trinary/TrinaryTests.cs
rename to exercises/practice/trinary/TrinaryTests.cs
diff --git a/exercises/twelve-days/.editorconfig b/exercises/practice/twelve-days/.editorconfig
similarity index 100%
rename from exercises/twelve-days/.editorconfig
rename to exercises/practice/twelve-days/.editorconfig
diff --git a/exercises/twelve-days/.meta/hints.md b/exercises/practice/twelve-days/.meta/hints.md
similarity index 100%
rename from exercises/twelve-days/.meta/hints.md
rename to exercises/practice/twelve-days/.meta/hints.md
diff --git a/exercises/twelve-days/.meta/tests.toml b/exercises/practice/twelve-days/.meta/tests.toml
similarity index 100%
rename from exercises/twelve-days/.meta/tests.toml
rename to exercises/practice/twelve-days/.meta/tests.toml
diff --git a/exercises/twelve-days/Example.cs b/exercises/practice/twelve-days/Example.cs
similarity index 100%
rename from exercises/twelve-days/Example.cs
rename to exercises/practice/twelve-days/Example.cs
diff --git a/exercises/twelve-days/README.md b/exercises/practice/twelve-days/README.md
similarity index 100%
rename from exercises/twelve-days/README.md
rename to exercises/practice/twelve-days/README.md
diff --git a/exercises/twelve-days/TwelveDays.cs b/exercises/practice/twelve-days/TwelveDays.cs
similarity index 100%
rename from exercises/twelve-days/TwelveDays.cs
rename to exercises/practice/twelve-days/TwelveDays.cs
diff --git a/exercises/twelve-days/TwelveDays.csproj b/exercises/practice/twelve-days/TwelveDays.csproj
similarity index 100%
rename from exercises/twelve-days/TwelveDays.csproj
rename to exercises/practice/twelve-days/TwelveDays.csproj
diff --git a/exercises/twelve-days/TwelveDaysTests.cs b/exercises/practice/twelve-days/TwelveDaysTests.cs
similarity index 100%
rename from exercises/twelve-days/TwelveDaysTests.cs
rename to exercises/practice/twelve-days/TwelveDaysTests.cs
diff --git a/exercises/two-bucket/.editorconfig b/exercises/practice/two-bucket/.editorconfig
similarity index 100%
rename from exercises/two-bucket/.editorconfig
rename to exercises/practice/two-bucket/.editorconfig
diff --git a/exercises/two-bucket/.meta/tests.toml b/exercises/practice/two-bucket/.meta/tests.toml
similarity index 100%
rename from exercises/two-bucket/.meta/tests.toml
rename to exercises/practice/two-bucket/.meta/tests.toml
diff --git a/exercises/two-bucket/Example.cs b/exercises/practice/two-bucket/Example.cs
similarity index 100%
rename from exercises/two-bucket/Example.cs
rename to exercises/practice/two-bucket/Example.cs
diff --git a/exercises/two-bucket/README.md b/exercises/practice/two-bucket/README.md
similarity index 100%
rename from exercises/two-bucket/README.md
rename to exercises/practice/two-bucket/README.md
diff --git a/exercises/two-bucket/TwoBucket.cs b/exercises/practice/two-bucket/TwoBucket.cs
similarity index 100%
rename from exercises/two-bucket/TwoBucket.cs
rename to exercises/practice/two-bucket/TwoBucket.cs
diff --git a/exercises/two-bucket/TwoBucket.csproj b/exercises/practice/two-bucket/TwoBucket.csproj
similarity index 100%
rename from exercises/two-bucket/TwoBucket.csproj
rename to exercises/practice/two-bucket/TwoBucket.csproj
diff --git a/exercises/two-bucket/TwoBucketTests.cs b/exercises/practice/two-bucket/TwoBucketTests.cs
similarity index 100%
rename from exercises/two-bucket/TwoBucketTests.cs
rename to exercises/practice/two-bucket/TwoBucketTests.cs
diff --git a/exercises/two-fer/.editorconfig b/exercises/practice/two-fer/.editorconfig
similarity index 100%
rename from exercises/two-fer/.editorconfig
rename to exercises/practice/two-fer/.editorconfig
diff --git a/exercises/two-fer/.meta/tests.toml b/exercises/practice/two-fer/.meta/tests.toml
similarity index 100%
rename from exercises/two-fer/.meta/tests.toml
rename to exercises/practice/two-fer/.meta/tests.toml
diff --git a/exercises/two-fer/Example.cs b/exercises/practice/two-fer/Example.cs
similarity index 100%
rename from exercises/two-fer/Example.cs
rename to exercises/practice/two-fer/Example.cs
diff --git a/exercises/two-fer/README.md b/exercises/practice/two-fer/README.md
similarity index 100%
rename from exercises/two-fer/README.md
rename to exercises/practice/two-fer/README.md
diff --git a/exercises/two-fer/TwoFer.cs b/exercises/practice/two-fer/TwoFer.cs
similarity index 100%
rename from exercises/two-fer/TwoFer.cs
rename to exercises/practice/two-fer/TwoFer.cs
diff --git a/exercises/two-fer/TwoFer.csproj b/exercises/practice/two-fer/TwoFer.csproj
similarity index 100%
rename from exercises/two-fer/TwoFer.csproj
rename to exercises/practice/two-fer/TwoFer.csproj
diff --git a/exercises/two-fer/TwoFerTests.cs b/exercises/practice/two-fer/TwoFerTests.cs
similarity index 100%
rename from exercises/two-fer/TwoFerTests.cs
rename to exercises/practice/two-fer/TwoFerTests.cs
diff --git a/exercises/variable-length-quantity/.editorconfig b/exercises/practice/variable-length-quantity/.editorconfig
similarity index 100%
rename from exercises/variable-length-quantity/.editorconfig
rename to exercises/practice/variable-length-quantity/.editorconfig
diff --git a/exercises/variable-length-quantity/.meta/hints.md b/exercises/practice/variable-length-quantity/.meta/hints.md
similarity index 100%
rename from exercises/variable-length-quantity/.meta/hints.md
rename to exercises/practice/variable-length-quantity/.meta/hints.md
diff --git a/exercises/variable-length-quantity/.meta/tests.toml b/exercises/practice/variable-length-quantity/.meta/tests.toml
similarity index 100%
rename from exercises/variable-length-quantity/.meta/tests.toml
rename to exercises/practice/variable-length-quantity/.meta/tests.toml
diff --git a/exercises/variable-length-quantity/Example.cs b/exercises/practice/variable-length-quantity/Example.cs
similarity index 100%
rename from exercises/variable-length-quantity/Example.cs
rename to exercises/practice/variable-length-quantity/Example.cs
diff --git a/exercises/variable-length-quantity/README.md b/exercises/practice/variable-length-quantity/README.md
similarity index 100%
rename from exercises/variable-length-quantity/README.md
rename to exercises/practice/variable-length-quantity/README.md
diff --git a/exercises/variable-length-quantity/VariableLengthQuantity.cs b/exercises/practice/variable-length-quantity/VariableLengthQuantity.cs
similarity index 100%
rename from exercises/variable-length-quantity/VariableLengthQuantity.cs
rename to exercises/practice/variable-length-quantity/VariableLengthQuantity.cs
diff --git a/exercises/variable-length-quantity/VariableLengthQuantity.csproj b/exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj
similarity index 100%
rename from exercises/variable-length-quantity/VariableLengthQuantity.csproj
rename to exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj
diff --git a/exercises/variable-length-quantity/VariableLengthQuantityTests.cs b/exercises/practice/variable-length-quantity/VariableLengthQuantityTests.cs
similarity index 100%
rename from exercises/variable-length-quantity/VariableLengthQuantityTests.cs
rename to exercises/practice/variable-length-quantity/VariableLengthQuantityTests.cs
diff --git a/exercises/word-count/.editorconfig b/exercises/practice/word-count/.editorconfig
similarity index 100%
rename from exercises/word-count/.editorconfig
rename to exercises/practice/word-count/.editorconfig
diff --git a/exercises/word-count/.meta/tests.toml b/exercises/practice/word-count/.meta/tests.toml
similarity index 100%
rename from exercises/word-count/.meta/tests.toml
rename to exercises/practice/word-count/.meta/tests.toml
diff --git a/exercises/word-count/Example.cs b/exercises/practice/word-count/Example.cs
similarity index 100%
rename from exercises/word-count/Example.cs
rename to exercises/practice/word-count/Example.cs
diff --git a/exercises/word-count/README.md b/exercises/practice/word-count/README.md
similarity index 100%
rename from exercises/word-count/README.md
rename to exercises/practice/word-count/README.md
diff --git a/exercises/word-count/WordCount.cs b/exercises/practice/word-count/WordCount.cs
similarity index 100%
rename from exercises/word-count/WordCount.cs
rename to exercises/practice/word-count/WordCount.cs
diff --git a/exercises/word-count/WordCount.csproj b/exercises/practice/word-count/WordCount.csproj
similarity index 100%
rename from exercises/word-count/WordCount.csproj
rename to exercises/practice/word-count/WordCount.csproj
diff --git a/exercises/word-count/WordCountTests.cs b/exercises/practice/word-count/WordCountTests.cs
similarity index 100%
rename from exercises/word-count/WordCountTests.cs
rename to exercises/practice/word-count/WordCountTests.cs
diff --git a/exercises/word-search/.editorconfig b/exercises/practice/word-search/.editorconfig
similarity index 100%
rename from exercises/word-search/.editorconfig
rename to exercises/practice/word-search/.editorconfig
diff --git a/exercises/word-search/.meta/hints.md b/exercises/practice/word-search/.meta/hints.md
similarity index 100%
rename from exercises/word-search/.meta/hints.md
rename to exercises/practice/word-search/.meta/hints.md
diff --git a/exercises/word-search/.meta/tests.toml b/exercises/practice/word-search/.meta/tests.toml
similarity index 100%
rename from exercises/word-search/.meta/tests.toml
rename to exercises/practice/word-search/.meta/tests.toml
diff --git a/exercises/word-search/Example.cs b/exercises/practice/word-search/Example.cs
similarity index 100%
rename from exercises/word-search/Example.cs
rename to exercises/practice/word-search/Example.cs
diff --git a/exercises/word-search/README.md b/exercises/practice/word-search/README.md
similarity index 100%
rename from exercises/word-search/README.md
rename to exercises/practice/word-search/README.md
diff --git a/exercises/word-search/WordSearch.cs b/exercises/practice/word-search/WordSearch.cs
similarity index 100%
rename from exercises/word-search/WordSearch.cs
rename to exercises/practice/word-search/WordSearch.cs
diff --git a/exercises/word-search/WordSearch.csproj b/exercises/practice/word-search/WordSearch.csproj
similarity index 100%
rename from exercises/word-search/WordSearch.csproj
rename to exercises/practice/word-search/WordSearch.csproj
diff --git a/exercises/word-search/WordSearchTests.cs b/exercises/practice/word-search/WordSearchTests.cs
similarity index 100%
rename from exercises/word-search/WordSearchTests.cs
rename to exercises/practice/word-search/WordSearchTests.cs
diff --git a/exercises/wordy/.editorconfig b/exercises/practice/wordy/.editorconfig
similarity index 100%
rename from exercises/wordy/.editorconfig
rename to exercises/practice/wordy/.editorconfig
diff --git a/exercises/wordy/.meta/hints.md b/exercises/practice/wordy/.meta/hints.md
similarity index 100%
rename from exercises/wordy/.meta/hints.md
rename to exercises/practice/wordy/.meta/hints.md
diff --git a/exercises/wordy/.meta/tests.toml b/exercises/practice/wordy/.meta/tests.toml
similarity index 100%
rename from exercises/wordy/.meta/tests.toml
rename to exercises/practice/wordy/.meta/tests.toml
diff --git a/exercises/wordy/Example.cs b/exercises/practice/wordy/Example.cs
similarity index 100%
rename from exercises/wordy/Example.cs
rename to exercises/practice/wordy/Example.cs
diff --git a/exercises/wordy/README.md b/exercises/practice/wordy/README.md
similarity index 100%
rename from exercises/wordy/README.md
rename to exercises/practice/wordy/README.md
diff --git a/exercises/wordy/Wordy.cs b/exercises/practice/wordy/Wordy.cs
similarity index 100%
rename from exercises/wordy/Wordy.cs
rename to exercises/practice/wordy/Wordy.cs
diff --git a/exercises/wordy/Wordy.csproj b/exercises/practice/wordy/Wordy.csproj
similarity index 100%
rename from exercises/wordy/Wordy.csproj
rename to exercises/practice/wordy/Wordy.csproj
diff --git a/exercises/wordy/WordyTests.cs b/exercises/practice/wordy/WordyTests.cs
similarity index 100%
rename from exercises/wordy/WordyTests.cs
rename to exercises/practice/wordy/WordyTests.cs
diff --git a/exercises/yacht/.editorconfig b/exercises/practice/yacht/.editorconfig
similarity index 100%
rename from exercises/yacht/.editorconfig
rename to exercises/practice/yacht/.editorconfig
diff --git a/exercises/yacht/.meta/tests.toml b/exercises/practice/yacht/.meta/tests.toml
similarity index 100%
rename from exercises/yacht/.meta/tests.toml
rename to exercises/practice/yacht/.meta/tests.toml
diff --git a/exercises/yacht/Example.cs b/exercises/practice/yacht/Example.cs
similarity index 100%
rename from exercises/yacht/Example.cs
rename to exercises/practice/yacht/Example.cs
diff --git a/exercises/yacht/README.md b/exercises/practice/yacht/README.md
similarity index 100%
rename from exercises/yacht/README.md
rename to exercises/practice/yacht/README.md
diff --git a/exercises/yacht/Yacht.cs b/exercises/practice/yacht/Yacht.cs
similarity index 100%
rename from exercises/yacht/Yacht.cs
rename to exercises/practice/yacht/Yacht.cs
diff --git a/exercises/yacht/Yacht.csproj b/exercises/practice/yacht/Yacht.csproj
similarity index 100%
rename from exercises/yacht/Yacht.csproj
rename to exercises/practice/yacht/Yacht.csproj
diff --git a/exercises/yacht/YachtTests.cs b/exercises/practice/yacht/YachtTests.cs
similarity index 100%
rename from exercises/yacht/YachtTests.cs
rename to exercises/practice/yacht/YachtTests.cs
diff --git a/exercises/zebra-puzzle/.editorconfig b/exercises/practice/zebra-puzzle/.editorconfig
similarity index 100%
rename from exercises/zebra-puzzle/.editorconfig
rename to exercises/practice/zebra-puzzle/.editorconfig
diff --git a/exercises/zebra-puzzle/.meta/hints.md b/exercises/practice/zebra-puzzle/.meta/hints.md
similarity index 100%
rename from exercises/zebra-puzzle/.meta/hints.md
rename to exercises/practice/zebra-puzzle/.meta/hints.md
diff --git a/exercises/zebra-puzzle/.meta/tests.toml b/exercises/practice/zebra-puzzle/.meta/tests.toml
similarity index 100%
rename from exercises/zebra-puzzle/.meta/tests.toml
rename to exercises/practice/zebra-puzzle/.meta/tests.toml
diff --git a/exercises/zebra-puzzle/Example.cs b/exercises/practice/zebra-puzzle/Example.cs
similarity index 100%
rename from exercises/zebra-puzzle/Example.cs
rename to exercises/practice/zebra-puzzle/Example.cs
diff --git a/exercises/zebra-puzzle/README.md b/exercises/practice/zebra-puzzle/README.md
similarity index 100%
rename from exercises/zebra-puzzle/README.md
rename to exercises/practice/zebra-puzzle/README.md
diff --git a/exercises/zebra-puzzle/ZebraPuzzle.cs b/exercises/practice/zebra-puzzle/ZebraPuzzle.cs
similarity index 100%
rename from exercises/zebra-puzzle/ZebraPuzzle.cs
rename to exercises/practice/zebra-puzzle/ZebraPuzzle.cs
diff --git a/exercises/zebra-puzzle/ZebraPuzzle.csproj b/exercises/practice/zebra-puzzle/ZebraPuzzle.csproj
similarity index 100%
rename from exercises/zebra-puzzle/ZebraPuzzle.csproj
rename to exercises/practice/zebra-puzzle/ZebraPuzzle.csproj
diff --git a/exercises/zebra-puzzle/ZebraPuzzleTests.cs b/exercises/practice/zebra-puzzle/ZebraPuzzleTests.cs
similarity index 100%
rename from exercises/zebra-puzzle/ZebraPuzzleTests.cs
rename to exercises/practice/zebra-puzzle/ZebraPuzzleTests.cs
diff --git a/exercises/zipper/.editorconfig b/exercises/practice/zipper/.editorconfig
similarity index 100%
rename from exercises/zipper/.editorconfig
rename to exercises/practice/zipper/.editorconfig
diff --git a/exercises/zipper/.meta/hints.md b/exercises/practice/zipper/.meta/hints.md
similarity index 100%
rename from exercises/zipper/.meta/hints.md
rename to exercises/practice/zipper/.meta/hints.md
diff --git a/exercises/zipper/.meta/tests.toml b/exercises/practice/zipper/.meta/tests.toml
similarity index 100%
rename from exercises/zipper/.meta/tests.toml
rename to exercises/practice/zipper/.meta/tests.toml
diff --git a/exercises/zipper/Example.cs b/exercises/practice/zipper/Example.cs
similarity index 100%
rename from exercises/zipper/Example.cs
rename to exercises/practice/zipper/Example.cs
diff --git a/exercises/zipper/README.md b/exercises/practice/zipper/README.md
similarity index 100%
rename from exercises/zipper/README.md
rename to exercises/practice/zipper/README.md
diff --git a/exercises/zipper/Zipper.cs b/exercises/practice/zipper/Zipper.cs
similarity index 100%
rename from exercises/zipper/Zipper.cs
rename to exercises/practice/zipper/Zipper.cs
diff --git a/exercises/zipper/Zipper.csproj b/exercises/practice/zipper/Zipper.csproj
similarity index 100%
rename from exercises/zipper/Zipper.csproj
rename to exercises/practice/zipper/Zipper.csproj
diff --git a/exercises/zipper/ZipperTests.cs b/exercises/practice/zipper/ZipperTests.cs
similarity index 100%
rename from exercises/zipper/ZipperTests.cs
rename to exercises/practice/zipper/ZipperTests.cs

From d758bed1ad988df48adf562e97feae9f491fac77 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:48 +0100
Subject: [PATCH 299/327] [v3] Add version property to config.json

---
 config.json | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/config.json b/config.json
index 75f5e5f1f2..6b3821fb7d 100644
--- a/config.json
+++ b/config.json
@@ -2,9 +2,10 @@
   "language": "C#",
   "active": true,
   "blurb": "C# is a modern, object-oriented language with lots of great features, such as type-inference and async/await. The tooling is excellent, and there is extensive, well-written documentation.",
-  "online_editor": {	
-    "indent_style": "space",	
-    "indent_size": 4	
+  "version": 3,
+  "online_editor": {
+    "indent_style": "space",
+    "indent_size": 4
   },
   "foregone": [
     "lens-person",

From dab25a6a0d2505433bfd0e195d9c098f368cfeed Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:48 +0100
Subject: [PATCH 300/327] [v3] Add status to config.json

---
 config.json | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/config.json b/config.json
index 6b3821fb7d..0a69aabf99 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,12 @@
 {
   "language": "C#",
   "active": true,
+  "status": {
+    "concept_exercises": false,
+    "test_runner": false,
+    "representer": false,
+    "analyzer": false
+  },
   "blurb": "C# is a modern, object-oriented language with lots of great features, such as type-inference and async/await. The tooling is excellent, and there is extensive, well-written documentation.",
   "version": 3,
   "online_editor": {

From c9543f24845a2ef33d79c51d6e1165f6968be987 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:49 +0100
Subject: [PATCH 301/327] [v3] Add slug to config.json

---
 config.json | 1 +
 1 file changed, 1 insertion(+)

diff --git a/config.json b/config.json
index 0a69aabf99..e08adf1a8c 100644
--- a/config.json
+++ b/config.json
@@ -1,5 +1,6 @@
 {
   "language": "C#",
+  "slug": "csharp",
   "active": true,
   "status": {
     "concept_exercises": false,

From 8661dac97bed340c5a653078f6e7ebeaeef9a5b5 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:49 +0100
Subject: [PATCH 302/327] [v3] Add status for deprecated practice exercises in
 config.json

---
 config.json | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/config.json b/config.json
index e08adf1a8c..c37ed780b8 100644
--- a/config.json
+++ b/config.json
@@ -1337,7 +1337,8 @@
       "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true
+      "deprecated": true,
+      "status": "deprecated"
     },
     {
       "slug": "trinary",
@@ -1346,7 +1347,8 @@
       "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true
+      "deprecated": true,
+      "status": "deprecated"
     },
     {
       "slug": "octal",
@@ -1355,7 +1357,8 @@
       "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true
+      "deprecated": true,
+      "status": "deprecated"
     },
     {
       "slug": "hexadecimal",
@@ -1364,7 +1367,8 @@
       "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true
+      "deprecated": true,
+      "status": "deprecated"
     },
     {
       "slug": "affine-cipher",

From ea8be386f89c63a189e73fd069ad8cb8de4a457c Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:49 +0100
Subject: [PATCH 303/327] [v3] Re-order practice exercises in config.json

---
 config.json | 1112 +++++++++++++++++++++++++--------------------------
 1 file changed, 556 insertions(+), 556 deletions(-)

diff --git a/config.json b/config.json
index c37ed780b8..ccaaf3820b 100644
--- a/config.json
+++ b/config.json
@@ -263,48 +263,56 @@
       ]
     },
     {
-      "slug": "reverse-string",
-      "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
+      "slug": "pangram",
+      "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
       "core": false,
-      "unlocked_by": null,
-      "difficulty": 1,
+      "unlocked_by": "hello-world",
+      "difficulty": 2,
       "topics": [
         "strings"
       ]
     },
     {
-      "slug": "sum-of-multiples",
-      "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
+      "slug": "isogram",
+      "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 1,
+      "unlocked_by": "two-fer",
+      "difficulty": 3,
       "topics": [
-        "arrays",
-        "math",
-        "transforming"
+        "filtering",
+        "strings"
       ]
     },
     {
-      "slug": "series",
-      "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
+      "slug": "acronym",
+      "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 1,
+      "unlocked_by": "two-fer",
+      "difficulty": 4,
       "topics": [
-        "arrays",
-        "strings"
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "accumulate",
-      "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
+      "slug": "grains",
+      "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
       "core": false,
-      "unlocked_by": "resistor-color",
+      "unlocked_by": "leap",
       "difficulty": 2,
       "topics": [
-        "extension_methods",
-        "sequences",
-        "transforming"
+        "integers"
+      ]
+    },
+    {
+      "slug": "perfect-numbers",
+      "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
+      "core": false,
+      "unlocked_by": "leap",
+      "difficulty": 3,
+      "topics": [
+        "integers",
+        "math"
       ]
     },
     {
@@ -322,34 +330,34 @@
       ]
     },
     {
-      "slug": "armstrong-numbers",
-      "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
+      "slug": "phone-number",
+      "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
       "core": false,
-      "unlocked_by": "space-age",
-      "difficulty": 2,
+      "unlocked_by": "gigasecond",
+      "difficulty": 3,
       "topics": [
-        "math"
+        "parsing",
+        "transforming"
       ]
     },
     {
-      "slug": "rational-numbers",
-      "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
+      "slug": "scrabble-score",
+      "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
       "core": false,
-      "unlocked_by": "space-age",
-      "difficulty": 4,
+      "unlocked_by": "gigasecond",
+      "difficulty": 3,
       "topics": [
-        "math"
+        "transforming"
       ]
     },
     {
-      "slug": "rna-transcription",
-      "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
+      "slug": "meetup",
+      "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
       "core": false,
-      "unlocked_by": null,
-      "difficulty": 1,
+      "unlocked_by": "gigasecond",
+      "difficulty": 4,
       "topics": [
-        "strings",
-        "transforming"
+        "dates"
       ]
     },
     {
@@ -365,132 +373,139 @@
       ]
     },
     {
-      "slug": "grains",
-      "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
+      "slug": "resistor-color-duo",
+      "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
       "core": false,
-      "unlocked_by": "leap",
-      "difficulty": 2,
+      "unlocked_by": "resistor-color",
+      "difficulty": 1,
       "topics": [
-        "integers"
+        "arrays"
       ]
     },
     {
-      "slug": "pangram",
-      "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
+      "slug": "resistor-color-trio",
+      "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
       "core": false,
-      "unlocked_by": "hello-world",
-      "difficulty": 2,
+      "unlocked_by": "resistor-color",
+      "difficulty": 1,
       "topics": [
-        "strings"
+        "arrays",
+        "conditionals"
       ]
     },
     {
-      "slug": "etl",
-      "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
+      "slug": "series",
+      "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
       "core": false,
-      "unlocked_by": "nucleotide-count",
-      "difficulty": 2,
+      "unlocked_by": "resistor-color",
+      "difficulty": 1,
       "topics": [
-        "dictionaries",
-        "lists",
-        "transforming"
+        "arrays",
+        "strings"
       ]
     },
     {
-      "slug": "raindrops",
-      "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
+      "slug": "sum-of-multiples",
+      "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
       "core": false,
-      "unlocked_by": "high-scores",
-      "difficulty": 2,
+      "unlocked_by": "resistor-color",
+      "difficulty": 1,
       "topics": [
-        "filtering",
-        "strings"
+        "arrays",
+        "math",
+        "transforming"
       ]
     },
     {
-      "slug": "binary-search",
-      "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
+      "slug": "accumulate",
+      "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 2,
       "topics": [
-        "arrays",
-        "searching"
+        "extension_methods",
+        "sequences",
+        "transforming"
       ]
     },
     {
-      "slug": "phone-number",
-      "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
+      "slug": "all-your-base",
+      "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
       "core": false,
-      "unlocked_by": "gigasecond",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 4,
       "topics": [
-        "parsing",
+        "integers",
+        "math",
         "transforming"
       ]
     },
     {
-      "slug": "strain",
-      "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
+      "slug": "largest-series-product",
+      "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
       "core": false,
-      "unlocked_by": "high-scores",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 4,
       "topics": [
-        "filtering",
-        "sequences"
+        "integers",
+        "math",
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "scrabble-score",
-      "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
+      "slug": "pascals-triangle",
+      "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
       "core": false,
-      "unlocked_by": "gigasecond",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 4,
       "topics": [
-        "transforming"
+        "arrays",
+        "loops",
+        "math"
       ]
     },
     {
-      "slug": "proverb",
-      "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
+      "slug": "prime-factors",
+      "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
       "core": false,
-      "unlocked_by": "high-scores",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 4,
       "topics": [
-        "algorithms",
-        "strings"
+        "integers",
+        "math"
       ]
     },
     {
-      "slug": "protein-translation",
-      "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
+      "slug": "pythagorean-triplet",
+      "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
       "core": false,
-      "unlocked_by": "hamming",
-      "difficulty": 3,
+      "unlocked_by": "resistor-color",
+      "difficulty": 4,
       "topics": [
-        "lists",
-        "strings",
-        "transforming"
+        "integers",
+        "math",
+        "overloading"
       ]
     },
     {
-      "slug": "error-handling",
-      "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
+      "slug": "armstrong-numbers",
+      "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
       "core": false,
-      "unlocked_by": "bob",
-      "difficulty": 3,
+      "unlocked_by": "space-age",
+      "difficulty": 2,
       "topics": [
-        "exception_handling"
+        "math"
       ]
     },
     {
-      "slug": "perfect-numbers",
-      "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
+      "slug": "darts",
+      "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
       "core": false,
-      "unlocked_by": "leap",
-      "difficulty": 3,
+      "unlocked_by": "space-age",
+      "difficulty": 2,
       "topics": [
-        "integers",
+        "floating_point_numbers",
         "math"
       ]
     },
@@ -506,182 +521,160 @@
       ]
     },
     {
-      "slug": "beer-song",
-      "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
+      "slug": "rational-numbers",
+      "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
       "core": false,
-      "unlocked_by": "high-scores",
-      "difficulty": 3,
+      "unlocked_by": "space-age",
+      "difficulty": 4,
       "topics": [
-        "algorithms",
-        "strings"
+        "math"
       ]
     },
     {
-      "slug": "sieve",
-      "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
+      "slug": "complex-numbers",
+      "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
       "core": false,
-      "unlocked_by": "robot-name",
-      "difficulty": 3,
+      "unlocked_by": "space-age",
+      "difficulty": 6,
       "topics": [
-        "filtering",
-        "math"
+        "math",
+        "tuples"
       ]
     },
     {
-      "slug": "queen-attack",
-      "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
+      "slug": "raindrops",
+      "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
       "core": false,
-      "unlocked_by": "clock",
-      "difficulty": 3,
-      "topics": [
-        "classes"
-      ]
-    },
-    {
-      "slug": "robot-simulator",
-      "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
-      "core": false,
-      "unlocked_by": "clock",
-      "difficulty": 3,
-      "topics": [
-        "classes",
-        "enumerations"
-      ]
-    },
-    {
-      "slug": "isogram",
-      "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
-      "core": false,
-      "unlocked_by": "two-fer",
-      "difficulty": 3,
+      "unlocked_by": "high-scores",
+      "difficulty": 2,
       "topics": [
         "filtering",
         "strings"
       ]
     },
     {
-      "slug": "secret-handshake",
-      "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
+      "slug": "beer-song",
+      "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "high-scores",
       "difficulty": 3,
       "topics": [
-        "arrays",
-        "bitwise_operations"
+        "algorithms",
+        "strings"
       ]
     },
     {
-      "slug": "kindergarten-garden",
-      "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
+      "slug": "proverb",
+      "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "high-scores",
       "difficulty": 3,
       "topics": [
-        "enumerations",
-        "parsing"
+        "algorithms",
+        "strings"
       ]
     },
     {
-      "slug": "saddle-points",
-      "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
+      "slug": "strain",
+      "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
       "core": false,
-      "unlocked_by": "circular-buffer",
-      "difficulty": 4,
+      "unlocked_by": "high-scores",
+      "difficulty": 3,
       "topics": [
-        "arrays",
-        "matrices",
-        "tuples"
+        "filtering",
+        "sequences"
       ]
     },
     {
-      "slug": "bank-account",
-      "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
+      "slug": "house",
+      "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
       "core": false,
-      "unlocked_by": "clock",
+      "unlocked_by": "high-scores",
       "difficulty": 4,
       "topics": [
-        "classes",
-        "concurrency"
+        "algorithms",
+        "strings"
       ]
     },
     {
-      "slug": "acronym",
-      "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
+      "slug": "protein-translation",
+      "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
       "core": false,
-      "unlocked_by": "two-fer",
-      "difficulty": 4,
+      "unlocked_by": "hamming",
+      "difficulty": 3,
       "topics": [
+        "lists",
         "strings",
         "transforming"
       ]
     },
     {
-      "slug": "simple-linked-list",
-      "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
+      "slug": "roman-numerals",
+      "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
       "core": false,
-      "unlocked_by": "clock",
-      "difficulty": 4,
+      "unlocked_by": "hamming",
+      "difficulty": 5,
       "topics": [
-        "classes",
-        "lists"
+        "loops",
+        "transforming"
       ]
     },
     {
-      "slug": "matrix",
-      "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
+      "slug": "simple-cipher",
+      "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 4,
+      "unlocked_by": "hamming",
+      "difficulty": 5,
       "topics": [
-        "matrices",
-        "parsing"
+        "algorithms",
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "largest-series-product",
-      "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
+      "slug": "etl",
+      "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 4,
+      "unlocked_by": "nucleotide-count",
+      "difficulty": 2,
       "topics": [
-        "integers",
-        "math",
-        "strings",
+        "dictionaries",
+        "lists",
         "transforming"
       ]
     },
     {
-      "slug": "house",
-      "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
+      "slug": "parallel-letter-frequency",
+      "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
       "core": false,
-      "unlocked_by": "high-scores",
-      "difficulty": 4,
+      "unlocked_by": "nucleotide-count",
+      "difficulty": 5,
       "topics": [
-        "algorithms",
-        "strings"
+        "dictionaries",
+        "parallelism",
+        "transforming"
       ]
     },
     {
-      "slug": "pythagorean-triplet",
-      "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
+      "slug": "alphametics",
+      "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 4,
+      "unlocked_by": "nucleotide-count",
+      "difficulty": 10,
       "topics": [
-        "integers",
-        "math",
-        "overloading"
+        "dictionaries",
+        "parsing"
       ]
     },
     {
-      "slug": "twelve-days",
-      "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
+      "slug": "sieve",
+      "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
       "core": false,
-      "unlocked_by": "bob",
-      "difficulty": 4,
+      "unlocked_by": "robot-name",
+      "difficulty": 3,
       "topics": [
-        "algorithms",
-        "strings"
+        "filtering",
+        "math"
       ]
     },
     {
@@ -696,209 +689,204 @@
       ]
     },
     {
-      "slug": "word-count",
-      "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
+      "slug": "binary-search",
+      "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
       "core": false,
-      "unlocked_by": "bob",
-      "difficulty": 4,
+      "unlocked_by": "allergies",
+      "difficulty": 3,
       "topics": [
-        "dictionaries",
-        "strings",
-        "transforming"
+        "arrays",
+        "searching"
       ]
     },
     {
-      "slug": "prime-factors",
-      "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
+      "slug": "kindergarten-garden",
+      "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 4,
+      "unlocked_by": "allergies",
+      "difficulty": 3,
       "topics": [
-        "integers",
-        "math"
+        "enumerations",
+        "parsing"
       ]
     },
     {
-      "slug": "meetup",
-      "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
+      "slug": "secret-handshake",
+      "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
       "core": false,
-      "unlocked_by": "gigasecond",
-      "difficulty": 4,
+      "unlocked_by": "allergies",
+      "difficulty": 3,
       "topics": [
-        "dates"
+        "arrays",
+        "bitwise_operations"
       ]
     },
     {
-      "slug": "all-your-base",
-      "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
+      "slug": "matrix",
+      "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
       "core": false,
-      "unlocked_by": "resistor-color",
+      "unlocked_by": "allergies",
       "difficulty": 4,
       "topics": [
-        "integers",
-        "math",
-        "transforming"
+        "matrices",
+        "parsing"
       ]
     },
     {
-      "slug": "pascals-triangle",
-      "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
+      "slug": "crypto-square",
+      "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
       "core": false,
-      "unlocked_by": "resistor-color",
-      "difficulty": 4,
+      "unlocked_by": "allergies",
+      "difficulty": 5,
       "topics": [
-        "arrays",
-        "loops",
-        "math"
+        "algorithms",
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "isbn-verifier",
-      "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
+      "slug": "food-chain",
+      "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
       "core": false,
-      "unlocked_by": "bob",
-      "difficulty": 4,
+      "unlocked_by": "allergies",
+      "difficulty": 5,
       "topics": [
-        "conditionals",
-        "loops",
-        "pattern_matching",
+        "algorithms",
         "strings"
       ]
     },
     {
-      "slug": "markdown",
-      "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
+      "slug": "minesweeper",
+      "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
       "core": false,
-      "unlocked_by": "spiral-matrix",
+      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "parsing",
-        "refactoring",
         "transforming"
       ]
     },
     {
-      "slug": "book-store",
-      "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
+      "slug": "scale-generator",
+      "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
       "core": false,
-      "unlocked_by": "dominoes",
+      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
-        "recursion"
+        "algorithms",
+        "parsing"
       ]
     },
     {
-      "slug": "list-ops",
-      "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
+      "slug": "tree-building",
+      "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
       "core": false,
-      "unlocked_by": "grade-school",
+      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
-        "lists",
-        "recursion"
+        "refactoring",
+        "trees"
       ]
     },
     {
-      "slug": "simple-cipher",
-      "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
+      "slug": "change",
+      "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
       "core": false,
-      "unlocked_by": "hamming",
-      "difficulty": 5,
+      "unlocked_by": "allergies",
+      "difficulty": 6,
       "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
+        "arrays",
+        "integers"
       ]
     },
     {
-      "slug": "roman-numerals",
-      "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
+      "slug": "rectangles",
+      "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
       "core": false,
-      "unlocked_by": "hamming",
-      "difficulty": 5,
+      "unlocked_by": "allergies",
+      "difficulty": 7,
       "topics": [
-        "loops",
+        "parsing",
         "transforming"
       ]
     },
     {
-      "slug": "flatten-array",
-      "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
+      "slug": "wordy",
+      "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
       "core": false,
-      "unlocked_by": "grade-school",
-      "difficulty": 5,
+      "unlocked_by": "allergies",
+      "difficulty": 7,
       "topics": [
-        "lists",
-        "recursion"
+        "parsing",
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "binary-search-tree",
-      "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
+      "slug": "connect",
+      "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
       "core": false,
-      "unlocked_by": "grade-school",
-      "difficulty": 5,
+      "unlocked_by": "allergies",
+      "difficulty": 8,
       "topics": [
-        "searching",
-        "trees"
+        "parsing",
+        "transforming"
       ]
     },
     {
-      "slug": "minesweeper",
-      "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
+      "slug": "sgf-parsing",
+      "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
       "core": false,
       "unlocked_by": "allergies",
-      "difficulty": 5,
+      "difficulty": 9,
       "topics": [
         "parsing",
         "transforming"
       ]
     },
     {
-      "slug": "parallel-letter-frequency",
-      "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
+      "slug": "atbash-cipher",
+      "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
       "core": false,
-      "unlocked_by": "nucleotide-count",
+      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
-        "dictionaries",
-        "parallelism",
+        "algorithms",
+        "strings",
         "transforming"
       ]
     },
     {
-      "slug": "atbash-cipher",
-      "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
+      "slug": "binary-search-tree",
+      "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
       "core": false,
       "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
+        "searching",
+        "trees"
       ]
     },
     {
-      "slug": "food-chain",
-      "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
+      "slug": "flatten-array",
+      "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
-        "algorithms",
-        "strings"
+        "lists",
+        "recursion"
       ]
     },
     {
-      "slug": "grep",
-      "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
+      "slug": "list-ops",
+      "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
       "core": false,
-      "unlocked_by": "spiral-matrix",
+      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
-        "files",
-        "searching",
-        "strings"
+        "lists",
+        "recursion"
       ]
     },
     {
@@ -912,115 +900,194 @@
       ]
     },
     {
-      "slug": "tree-building",
-      "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
+      "slug": "ledger",
+      "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "rotational-cipher",
       "difficulty": 5,
       "topics": [
+        "globalization",
         "refactoring",
-        "trees"
+        "strings"
       ]
     },
     {
-      "slug": "scale-generator",
-      "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
+      "slug": "ocr-numbers",
+      "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "rotational-cipher",
       "difficulty": 5,
       "topics": [
-        "algorithms",
-        "parsing"
+        "parsing",
+        "pattern_recognition"
       ]
     },
     {
-      "slug": "linked-list",
-      "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
+      "slug": "saddle-points",
+      "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
       "core": false,
-      "unlocked_by": "matching-brackets",
-      "difficulty": 5,
+      "unlocked_by": "circular-buffer",
+      "difficulty": 4,
       "topics": [
-        "classes",
-        "lists"
+        "arrays",
+        "matrices",
+        "tuples"
       ]
     },
     {
-      "slug": "crypto-square",
-      "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
+      "slug": "palindrome-products",
+      "uuid": "165b8599-726d-43dd-8511-1401525810de",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 5,
+      "unlocked_by": "circular-buffer",
+      "difficulty": 6,
       "topics": [
         "algorithms",
+        "math",
         "strings",
-        "transforming"
+        "tuples"
       ]
     },
     {
-      "slug": "ledger",
-      "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
+      "slug": "hangman",
+      "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
       "core": false,
-      "unlocked_by": "rotational-cipher",
-      "difficulty": 5,
+      "unlocked_by": "circular-buffer",
+      "difficulty": 8,
       "topics": [
-        "globalization",
-        "refactoring",
-        "strings"
+        "events",
+        "reactive_programming"
       ]
     },
     {
-      "slug": "custom-set",
-      "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
+      "slug": "two-bucket",
+      "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
       "core": false,
-      "unlocked_by": "dominoes",
-      "difficulty": 5,
+      "unlocked_by": "circular-buffer",
+      "difficulty": 8,
       "topics": [
-        "sets"
+        "logic"
       ]
     },
     {
-      "slug": "dot-dsl",
-      "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
+      "slug": "go-counting",
+      "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
       "core": false,
-      "unlocked_by": "matching-brackets",
-      "difficulty": 5,
+      "unlocked_by": "circular-buffer",
+      "difficulty": 9,
+      "topics": [
+        "optional_values",
+        "parsing",
+        "tuples"
+      ]
+    },
+    {
+      "slug": "dnd-character",
+      "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
+      "core": false,
+      "unlocked_by": "clock",
+      "difficulty": 3,
+      "topics": [
+        "randomness"
+      ]
+    },
+    {
+      "slug": "queen-attack",
+      "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
+      "core": false,
+      "unlocked_by": "clock",
+      "difficulty": 3,
+      "topics": [
+        "classes"
+      ]
+    },
+    {
+      "slug": "robot-simulator",
+      "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
+      "core": false,
+      "unlocked_by": "clock",
+      "difficulty": 3,
       "topics": [
         "classes",
-        "domain_specific_languages",
-        "equality"
+        "enumerations"
       ]
     },
     {
-      "slug": "ocr-numbers",
-      "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
+      "slug": "bank-account",
+      "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
       "core": false,
-      "unlocked_by": "rotational-cipher",
-      "difficulty": 5,
+      "unlocked_by": "clock",
+      "difficulty": 4,
       "topics": [
-        "parsing",
-        "pattern_recognition"
+        "classes",
+        "concurrency"
       ]
     },
     {
-      "slug": "luhn",
-      "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
+      "slug": "simple-linked-list",
+      "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
       "core": false,
-      "unlocked_by": "spiral-matrix",
-      "difficulty": 5,
+      "unlocked_by": "clock",
+      "difficulty": 4,
       "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
+        "classes",
+        "lists"
       ]
     },
     {
-      "slug": "run-length-encoding",
-      "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
+      "slug": "error-handling",
+      "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
       "core": false,
-      "unlocked_by": "variable-length-quantity",
-      "difficulty": 5,
+      "unlocked_by": "bob",
+      "difficulty": 3,
+      "topics": [
+        "exception_handling"
+      ]
+    },
+    {
+      "slug": "affine-cipher",
+      "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
+      "core": false,
+      "unlocked_by": "bob",
+      "difficulty": 4,
+      "topics": [
+        "cryptography",
+        "math",
+        "strings"
+      ]
+    },
+    {
+      "slug": "isbn-verifier",
+      "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
+      "core": false,
+      "unlocked_by": "bob",
+      "difficulty": 4,
+      "topics": [
+        "conditionals",
+        "loops",
+        "pattern_matching",
+        "strings"
+      ]
+    },
+    {
+      "slug": "twelve-days",
+      "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
+      "core": false,
+      "unlocked_by": "bob",
+      "difficulty": 4,
       "topics": [
         "algorithms",
+        "strings"
+      ]
+    },
+    {
+      "slug": "word-count",
+      "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
+      "core": false,
+      "unlocked_by": "bob",
+      "difficulty": 4,
+      "topics": [
+        "dictionaries",
+        "strings",
         "transforming"
       ]
     },
@@ -1037,104 +1104,106 @@
       ]
     },
     {
-      "slug": "word-search",
-      "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
+      "slug": "dot-dsl",
+      "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
       "core": false,
-      "unlocked_by": "spiral-matrix",
-      "difficulty": 6,
+      "unlocked_by": "matching-brackets",
+      "difficulty": 5,
       "topics": [
-        "searching",
-        "tuples"
+        "classes",
+        "domain_specific_languages",
+        "equality"
       ]
     },
     {
-      "slug": "bowling",
-      "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
+      "slug": "linked-list",
+      "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
       "core": false,
-      "unlocked_by": "tournament",
-      "difficulty": 6,
+      "unlocked_by": "matching-brackets",
+      "difficulty": 5,
       "topics": [
-        "algorithms",
-        "loops"
+        "classes",
+        "lists"
       ]
     },
     {
-      "slug": "transpose",
-      "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
+      "slug": "diamond",
+      "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
       "core": false,
-      "unlocked_by": "variable-length-quantity",
-      "difficulty": 6,
+      "unlocked_by": "matching-brackets",
+      "difficulty": 8,
       "topics": [
-        "strings",
-        "transforming"
+        "algorithms",
+        "strings"
       ]
     },
     {
-      "slug": "nth-prime",
-      "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
+      "slug": "grep",
+      "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
       "core": false,
-      "unlocked_by": "dominoes",
-      "difficulty": 6,
+      "unlocked_by": "spiral-matrix",
+      "difficulty": 5,
       "topics": [
-        "math"
+        "files",
+        "searching",
+        "strings"
       ]
     },
     {
-      "slug": "pig-latin",
-      "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
+      "slug": "luhn",
+      "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
       "core": false,
-      "unlocked_by": "variable-length-quantity",
-      "difficulty": 6,
+      "unlocked_by": "spiral-matrix",
+      "difficulty": 5,
       "topics": [
+        "algorithms",
         "strings",
         "transforming"
       ]
     },
     {
-      "slug": "rail-fence-cipher",
-      "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
+      "slug": "markdown",
+      "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
       "core": false,
-      "unlocked_by": "dominoes",
-      "difficulty": 6,
+      "unlocked_by": "spiral-matrix",
+      "difficulty": 5,
       "topics": [
-        "algorithms",
-        "strings",
+        "parsing",
+        "refactoring",
         "transforming"
       ]
     },
     {
-      "slug": "change",
-      "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
+      "slug": "word-search",
+      "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
       "core": false,
-      "unlocked_by": "allergies",
+      "unlocked_by": "spiral-matrix",
       "difficulty": 6,
       "topics": [
-        "arrays",
-        "integers"
+        "searching",
+        "tuples"
       ]
     },
     {
-      "slug": "palindrome-products",
-      "uuid": "165b8599-726d-43dd-8511-1401525810de",
+      "slug": "bowling",
+      "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
       "core": false,
-      "unlocked_by": "circular-buffer",
+      "unlocked_by": "tournament",
       "difficulty": 6,
       "topics": [
         "algorithms",
-        "math",
-        "strings",
-        "tuples"
+        "loops"
       ]
     },
     {
-      "slug": "complex-numbers",
-      "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
+      "slug": "rest-api",
+      "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
       "core": false,
-      "unlocked_by": "space-age",
+      "unlocked_by": "tournament",
       "difficulty": 6,
       "topics": [
-        "math",
-        "tuples"
+        "json",
+        "parsing"
       ]
     },
     {
@@ -1150,105 +1219,114 @@
       ]
     },
     {
-      "slug": "diffie-hellman",
-      "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
+      "slug": "run-length-encoding",
+      "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
       "core": false,
-      "unlocked_by": "dominoes",
-      "difficulty": 7,
+      "unlocked_by": "variable-length-quantity",
+      "difficulty": 5,
       "topics": [
         "algorithms",
-        "integers",
-        "math",
         "transforming"
       ]
     },
     {
-      "slug": "rectangles",
-      "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
+      "slug": "pig-latin",
+      "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 7,
+      "unlocked_by": "variable-length-quantity",
+      "difficulty": 6,
       "topics": [
-        "parsing",
+        "strings",
         "transforming"
       ]
     },
     {
-      "slug": "wordy",
-      "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
+      "slug": "transpose",
+      "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 7,
+      "unlocked_by": "variable-length-quantity",
+      "difficulty": 6,
       "topics": [
-        "parsing",
         "strings",
         "transforming"
       ]
     },
     {
-      "slug": "zebra-puzzle",
-      "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
+      "slug": "say",
+      "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
       "core": false,
-      "unlocked_by": "dominoes",
+      "unlocked_by": "variable-length-quantity",
       "difficulty": 8,
       "topics": [
-        "logic"
+        "strings",
+        "transforming"
       ]
     },
     {
-      "slug": "hangman",
-      "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
+      "slug": "book-store",
+      "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
       "core": false,
-      "unlocked_by": "circular-buffer",
-      "difficulty": 8,
+      "unlocked_by": "dominoes",
+      "difficulty": 5,
       "topics": [
-        "events",
-        "reactive_programming"
+        "recursion"
       ]
     },
     {
-      "slug": "diamond",
-      "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
+      "slug": "custom-set",
+      "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
       "core": false,
-      "unlocked_by": "matching-brackets",
-      "difficulty": 8,
+      "unlocked_by": "dominoes",
+      "difficulty": 5,
       "topics": [
-        "algorithms",
-        "strings"
+        "sets"
       ]
     },
     {
-      "slug": "two-bucket",
-      "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
+      "slug": "nth-prime",
+      "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
       "core": false,
-      "unlocked_by": "circular-buffer",
-      "difficulty": 8,
+      "unlocked_by": "dominoes",
+      "difficulty": 6,
       "topics": [
-        "logic"
+        "math"
       ]
     },
     {
-      "slug": "connect",
-      "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
+      "slug": "rail-fence-cipher",
+      "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
       "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 8,
+      "unlocked_by": "dominoes",
+      "difficulty": 6,
       "topics": [
-        "parsing",
+        "algorithms",
+        "strings",
         "transforming"
       ]
     },
     {
-      "slug": "say",
-      "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
+      "slug": "diffie-hellman",
+      "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
       "core": false,
-      "unlocked_by": "variable-length-quantity",
-      "difficulty": 8,
+      "unlocked_by": "dominoes",
+      "difficulty": 7,
       "topics": [
-        "strings",
+        "algorithms",
+        "integers",
+        "math",
         "transforming"
       ]
     },
+    {
+      "slug": "zebra-puzzle",
+      "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
+      "core": false,
+      "unlocked_by": "dominoes",
+      "difficulty": 8,
+      "topics": [
+        "logic"
+      ]
+    },
     {
       "slug": "react",
       "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
@@ -1261,52 +1339,6 @@
         "reactive_programming"
       ]
     },
-    {
-      "slug": "go-counting",
-      "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
-      "core": false,
-      "unlocked_by": "circular-buffer",
-      "difficulty": 9,
-      "topics": [
-        "optional_values",
-        "parsing",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "sgf-parsing",
-      "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
-      "core": false,
-      "unlocked_by": "allergies",
-      "difficulty": 9,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "zipper",
-      "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
-      "core": false,
-      "unlocked_by": "forth",
-      "difficulty": 10,
-      "topics": [
-        "recursion",
-        "searching",
-        "trees"
-      ]
-    },
-    {
-      "slug": "alphametics",
-      "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
-      "core": false,
-      "unlocked_by": "nucleotide-count",
-      "difficulty": 10,
-      "topics": [
-        "dictionaries",
-        "parsing"
-      ]
-    },
     {
       "slug": "pov",
       "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
@@ -1320,14 +1352,15 @@
       ]
     },
     {
-      "slug": "rest-api",
-      "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
+      "slug": "zipper",
+      "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
       "core": false,
-      "unlocked_by": "tournament",
-      "difficulty": 6,
+      "unlocked_by": "forth",
+      "difficulty": 10,
       "topics": [
-        "json",
-        "parsing"
+        "recursion",
+        "searching",
+        "trees"
       ]
     },
     {
@@ -1341,8 +1374,8 @@
       "status": "deprecated"
     },
     {
-      "slug": "trinary",
-      "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
+      "slug": "hexadecimal",
+      "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
       "core": false,
       "unlocked_by": null,
       "difficulty": 0,
@@ -1361,8 +1394,8 @@
       "status": "deprecated"
     },
     {
-      "slug": "hexadecimal",
-      "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
+      "slug": "trinary",
+      "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
       "core": false,
       "unlocked_by": null,
       "difficulty": 0,
@@ -1371,57 +1404,24 @@
       "status": "deprecated"
     },
     {
-      "slug": "affine-cipher",
-      "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
-      "core": false,
-      "unlocked_by": "bob",
-      "difficulty": 4,
-      "topics": [
-        "cryptography",
-        "math",
-        "strings"
-      ]
-    },
-    {
-      "slug": "darts",
-      "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
-      "core": false,
-      "unlocked_by": "space-age",
-      "difficulty": 2,
-      "topics": [
-        "floating_point_numbers",
-        "math"
-      ]
-    },
-    {
-      "slug": "dnd-character",
-      "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
-      "core": false,
-      "unlocked_by": "clock",
-      "difficulty": 3,
-      "topics": [
-        "randomness"
-      ]
-    },
-    {
-      "slug": "resistor-color-duo",
-      "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
+      "slug": "reverse-string",
+      "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
       "core": false,
-      "unlocked_by": "resistor-color",
+      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
-        "arrays"
+        "strings"
       ]
     },
     {
-      "slug": "resistor-color-trio",
-      "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
+      "slug": "rna-transcription",
+      "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
       "core": false,
-      "unlocked_by": "resistor-color",
+      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
-        "arrays",
-        "conditionals"
+        "strings",
+        "transforming"
       ]
     }
   ]

From fbcd75fa9d3d14ca6ecff2a9c3a0f798439162a9 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:50 +0100
Subject: [PATCH 304/327] [v3] Remove deprecated properties from practice
 exercises in config.json

---
 config.json | 257 ----------------------------------------------------
 1 file changed, 257 deletions(-)

diff --git a/config.json b/config.json
index ccaaf3820b..086d2be760 100644
--- a/config.json
+++ b/config.json
@@ -25,9 +25,6 @@
     {
       "slug": "hello-world",
       "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
-      "core": true,
-      "auto_approve": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "strings"
@@ -36,8 +33,6 @@
     {
       "slug": "two-fer",
       "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "optional_values",
@@ -47,8 +42,6 @@
     {
       "slug": "leap",
       "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "conditionals",
@@ -58,8 +51,6 @@
     {
       "slug": "gigasecond",
       "uuid": "b7116dfb-1107-4546-9f95-f15acdb6f6a4",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "dates"
@@ -68,8 +59,6 @@
     {
       "slug": "resistor-color",
       "uuid": "5314dbee-4a0d-4fd6-a98a-36a746ee0d5c",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "arrays"
@@ -78,8 +67,6 @@
     {
       "slug": "space-age",
       "uuid": "612f058b-c6d9-4c97-913a-eeeb59ef61e1",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "floating_point_numbers"
@@ -88,8 +75,6 @@
     {
       "slug": "high-scores",
       "uuid": "f52d9be9-7044-4001-8678-dcae91a8d7f3",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "lists"
@@ -98,8 +83,6 @@
     {
       "slug": "hamming",
       "uuid": "05162ee0-38ac-40ad-a591-d70a74b6963a",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 2,
       "topics": [
         "filtering",
@@ -109,8 +92,6 @@
     {
       "slug": "nucleotide-count",
       "uuid": "caca1c6a-b998-431e-b6af-ca2d47b7708f",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 2,
       "topics": [
         "dictionaries",
@@ -120,8 +101,6 @@
     {
       "slug": "robot-name",
       "uuid": "46b8aea8-1528-43cb-a754-495ec2790ce2",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 3,
       "topics": [
         "classes",
@@ -132,8 +111,6 @@
     {
       "slug": "allergies",
       "uuid": "2ac228d8-7bf0-4946-8352-6541df02c0a2",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 3,
       "topics": [
         "bitwise_operations",
@@ -143,8 +120,6 @@
     {
       "slug": "grade-school",
       "uuid": "ec1cc254-8e66-40d0-87bf-971d54c541c4",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 3,
       "topics": [
         "lists",
@@ -154,8 +129,6 @@
     {
       "slug": "rotational-cipher",
       "uuid": "8a0a291d-8330-4901-bdbe-f974e163158e",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -166,8 +139,6 @@
     {
       "slug": "circular-buffer",
       "uuid": "657ac368-9b17-4f87-b815-decfe2bc0b5d",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 4,
       "topics": [
         "classes",
@@ -177,8 +148,6 @@
     {
       "slug": "clock",
       "uuid": "83e4cb1e-456f-4c74-ae82-6895f0bd73ae",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 4,
       "topics": [
         "classes",
@@ -188,8 +157,6 @@
     {
       "slug": "bob",
       "uuid": "da00f894-dbc8-485e-adba-a79d5ebee3ad",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 4,
       "topics": [
         "conditionals",
@@ -199,8 +166,6 @@
     {
       "slug": "matching-brackets",
       "uuid": "a2070019-e56d-4d48-994b-300411598707",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -210,8 +175,6 @@
     {
       "slug": "spiral-matrix",
       "uuid": "bae1f3a4-b63d-4efd-921a-133b3d5e379c",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -221,8 +184,6 @@
     {
       "slug": "tournament",
       "uuid": "d9359f25-dc94-496c-adc3-57fe541857fe",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 6,
       "topics": [
         "parsing",
@@ -232,8 +193,6 @@
     {
       "slug": "variable-length-quantity",
       "uuid": "4c49ea84-8765-42b0-b4ab-5dead802eeee",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 7,
       "topics": [
         "algorithms",
@@ -243,8 +202,6 @@
     {
       "slug": "dominoes",
       "uuid": "0409f45f-b65e-4404-a9e7-2ef432d834b2",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 8,
       "topics": [
         "arrays",
@@ -254,8 +211,6 @@
     {
       "slug": "forth",
       "uuid": "a2ba6202-f6e0-46f4-95e4-5921656f2e1a",
-      "core": true,
-      "unlocked_by": null,
       "difficulty": 10,
       "topics": [
         "parsing",
@@ -265,8 +220,6 @@
     {
       "slug": "pangram",
       "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
-      "core": false,
-      "unlocked_by": "hello-world",
       "difficulty": 2,
       "topics": [
         "strings"
@@ -275,8 +228,6 @@
     {
       "slug": "isogram",
       "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
-      "core": false,
-      "unlocked_by": "two-fer",
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -286,8 +237,6 @@
     {
       "slug": "acronym",
       "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
-      "core": false,
-      "unlocked_by": "two-fer",
       "difficulty": 4,
       "topics": [
         "strings",
@@ -297,8 +246,6 @@
     {
       "slug": "grains",
       "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
-      "core": false,
-      "unlocked_by": "leap",
       "difficulty": 2,
       "topics": [
         "integers"
@@ -307,8 +254,6 @@
     {
       "slug": "perfect-numbers",
       "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
-      "core": false,
-      "unlocked_by": "leap",
       "difficulty": 3,
       "topics": [
         "integers",
@@ -318,8 +263,6 @@
     {
       "slug": "collatz-conjecture",
       "uuid": "c4efbf8a-8e76-4700-807d-830a4938f4d0",
-      "core": false,
-      "unlocked_by": "gigasecond",
       "difficulty": 2,
       "topics": [
         "algorithms",
@@ -332,8 +275,6 @@
     {
       "slug": "phone-number",
       "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
-      "core": false,
-      "unlocked_by": "gigasecond",
       "difficulty": 3,
       "topics": [
         "parsing",
@@ -343,8 +284,6 @@
     {
       "slug": "scrabble-score",
       "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
-      "core": false,
-      "unlocked_by": "gigasecond",
       "difficulty": 3,
       "topics": [
         "transforming"
@@ -353,8 +292,6 @@
     {
       "slug": "meetup",
       "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
-      "core": false,
-      "unlocked_by": "gigasecond",
       "difficulty": 4,
       "topics": [
         "dates"
@@ -363,8 +300,6 @@
     {
       "slug": "difference-of-squares",
       "uuid": "5554c048-0de3-4a85-b043-7577f429cba4",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 1,
       "topics": [
         "integers",
@@ -375,8 +310,6 @@
     {
       "slug": "resistor-color-duo",
       "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 1,
       "topics": [
         "arrays"
@@ -385,8 +318,6 @@
     {
       "slug": "resistor-color-trio",
       "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -396,8 +327,6 @@
     {
       "slug": "series",
       "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -407,8 +336,6 @@
     {
       "slug": "sum-of-multiples",
       "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -419,8 +346,6 @@
     {
       "slug": "accumulate",
       "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 2,
       "topics": [
         "extension_methods",
@@ -431,8 +356,6 @@
     {
       "slug": "all-your-base",
       "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 4,
       "topics": [
         "integers",
@@ -443,8 +366,6 @@
     {
       "slug": "largest-series-product",
       "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 4,
       "topics": [
         "integers",
@@ -456,8 +377,6 @@
     {
       "slug": "pascals-triangle",
       "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 4,
       "topics": [
         "arrays",
@@ -468,8 +387,6 @@
     {
       "slug": "prime-factors",
       "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 4,
       "topics": [
         "integers",
@@ -479,8 +396,6 @@
     {
       "slug": "pythagorean-triplet",
       "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
-      "core": false,
-      "unlocked_by": "resistor-color",
       "difficulty": 4,
       "topics": [
         "integers",
@@ -491,8 +406,6 @@
     {
       "slug": "armstrong-numbers",
       "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
-      "core": false,
-      "unlocked_by": "space-age",
       "difficulty": 2,
       "topics": [
         "math"
@@ -501,8 +414,6 @@
     {
       "slug": "darts",
       "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
-      "core": false,
-      "unlocked_by": "space-age",
       "difficulty": 2,
       "topics": [
         "floating_point_numbers",
@@ -512,8 +423,6 @@
     {
       "slug": "triangle",
       "uuid": "5b1713c7-1597-4e67-ac97-f305b207bc38",
-      "core": false,
-      "unlocked_by": "space-age",
       "difficulty": 3,
       "topics": [
         "enumerations",
@@ -523,8 +432,6 @@
     {
       "slug": "rational-numbers",
       "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
-      "core": false,
-      "unlocked_by": "space-age",
       "difficulty": 4,
       "topics": [
         "math"
@@ -533,8 +440,6 @@
     {
       "slug": "complex-numbers",
       "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
-      "core": false,
-      "unlocked_by": "space-age",
       "difficulty": 6,
       "topics": [
         "math",
@@ -544,8 +449,6 @@
     {
       "slug": "raindrops",
       "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
-      "core": false,
-      "unlocked_by": "high-scores",
       "difficulty": 2,
       "topics": [
         "filtering",
@@ -555,8 +458,6 @@
     {
       "slug": "beer-song",
       "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
-      "core": false,
-      "unlocked_by": "high-scores",
       "difficulty": 3,
       "topics": [
         "algorithms",
@@ -566,8 +467,6 @@
     {
       "slug": "proverb",
       "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
-      "core": false,
-      "unlocked_by": "high-scores",
       "difficulty": 3,
       "topics": [
         "algorithms",
@@ -577,8 +476,6 @@
     {
       "slug": "strain",
       "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
-      "core": false,
-      "unlocked_by": "high-scores",
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -588,8 +485,6 @@
     {
       "slug": "house",
       "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
-      "core": false,
-      "unlocked_by": "high-scores",
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -599,8 +494,6 @@
     {
       "slug": "protein-translation",
       "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
-      "core": false,
-      "unlocked_by": "hamming",
       "difficulty": 3,
       "topics": [
         "lists",
@@ -611,8 +504,6 @@
     {
       "slug": "roman-numerals",
       "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
-      "core": false,
-      "unlocked_by": "hamming",
       "difficulty": 5,
       "topics": [
         "loops",
@@ -622,8 +513,6 @@
     {
       "slug": "simple-cipher",
       "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
-      "core": false,
-      "unlocked_by": "hamming",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -634,8 +523,6 @@
     {
       "slug": "etl",
       "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
-      "core": false,
-      "unlocked_by": "nucleotide-count",
       "difficulty": 2,
       "topics": [
         "dictionaries",
@@ -646,8 +533,6 @@
     {
       "slug": "parallel-letter-frequency",
       "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
-      "core": false,
-      "unlocked_by": "nucleotide-count",
       "difficulty": 5,
       "topics": [
         "dictionaries",
@@ -658,8 +543,6 @@
     {
       "slug": "alphametics",
       "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
-      "core": false,
-      "unlocked_by": "nucleotide-count",
       "difficulty": 10,
       "topics": [
         "dictionaries",
@@ -669,8 +552,6 @@
     {
       "slug": "sieve",
       "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
-      "core": false,
-      "unlocked_by": "robot-name",
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -680,8 +561,6 @@
     {
       "slug": "anagram",
       "uuid": "790216d1-4fd9-4a9b-94f8-e1e07a18c2b7",
-      "core": false,
-      "unlocked_by": "robot-name",
       "difficulty": 4,
       "topics": [
         "filtering",
@@ -691,8 +570,6 @@
     {
       "slug": "binary-search",
       "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 3,
       "topics": [
         "arrays",
@@ -702,8 +579,6 @@
     {
       "slug": "kindergarten-garden",
       "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 3,
       "topics": [
         "enumerations",
@@ -713,8 +588,6 @@
     {
       "slug": "secret-handshake",
       "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 3,
       "topics": [
         "arrays",
@@ -724,8 +597,6 @@
     {
       "slug": "matrix",
       "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 4,
       "topics": [
         "matrices",
@@ -735,8 +606,6 @@
     {
       "slug": "crypto-square",
       "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -747,8 +616,6 @@
     {
       "slug": "food-chain",
       "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -758,8 +625,6 @@
     {
       "slug": "minesweeper",
       "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -769,8 +634,6 @@
     {
       "slug": "scale-generator",
       "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -780,8 +643,6 @@
     {
       "slug": "tree-building",
       "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 5,
       "topics": [
         "refactoring",
@@ -791,8 +652,6 @@
     {
       "slug": "change",
       "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 6,
       "topics": [
         "arrays",
@@ -802,8 +661,6 @@
     {
       "slug": "rectangles",
       "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 7,
       "topics": [
         "parsing",
@@ -813,8 +670,6 @@
     {
       "slug": "wordy",
       "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 7,
       "topics": [
         "parsing",
@@ -825,8 +680,6 @@
     {
       "slug": "connect",
       "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 8,
       "topics": [
         "parsing",
@@ -836,8 +689,6 @@
     {
       "slug": "sgf-parsing",
       "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
-      "core": false,
-      "unlocked_by": "allergies",
       "difficulty": 9,
       "topics": [
         "parsing",
@@ -847,8 +698,6 @@
     {
       "slug": "atbash-cipher",
       "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
-      "core": false,
-      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -859,8 +708,6 @@
     {
       "slug": "binary-search-tree",
       "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
-      "core": false,
-      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
         "searching",
@@ -870,8 +717,6 @@
     {
       "slug": "flatten-array",
       "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
-      "core": false,
-      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
         "lists",
@@ -881,8 +726,6 @@
     {
       "slug": "list-ops",
       "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
-      "core": false,
-      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
         "lists",
@@ -892,8 +735,6 @@
     {
       "slug": "sublist",
       "uuid": "89d3b074-190f-4520-8f87-cde6368fc58e",
-      "core": false,
-      "unlocked_by": "grade-school",
       "difficulty": 5,
       "topics": [
         "lists"
@@ -902,8 +743,6 @@
     {
       "slug": "ledger",
       "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
-      "core": false,
-      "unlocked_by": "rotational-cipher",
       "difficulty": 5,
       "topics": [
         "globalization",
@@ -914,8 +753,6 @@
     {
       "slug": "ocr-numbers",
       "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
-      "core": false,
-      "unlocked_by": "rotational-cipher",
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -925,8 +762,6 @@
     {
       "slug": "saddle-points",
       "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
-      "core": false,
-      "unlocked_by": "circular-buffer",
       "difficulty": 4,
       "topics": [
         "arrays",
@@ -937,8 +772,6 @@
     {
       "slug": "palindrome-products",
       "uuid": "165b8599-726d-43dd-8511-1401525810de",
-      "core": false,
-      "unlocked_by": "circular-buffer",
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -950,8 +783,6 @@
     {
       "slug": "hangman",
       "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
-      "core": false,
-      "unlocked_by": "circular-buffer",
       "difficulty": 8,
       "topics": [
         "events",
@@ -961,8 +792,6 @@
     {
       "slug": "two-bucket",
       "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
-      "core": false,
-      "unlocked_by": "circular-buffer",
       "difficulty": 8,
       "topics": [
         "logic"
@@ -971,8 +800,6 @@
     {
       "slug": "go-counting",
       "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
-      "core": false,
-      "unlocked_by": "circular-buffer",
       "difficulty": 9,
       "topics": [
         "optional_values",
@@ -983,8 +810,6 @@
     {
       "slug": "dnd-character",
       "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
-      "core": false,
-      "unlocked_by": "clock",
       "difficulty": 3,
       "topics": [
         "randomness"
@@ -993,8 +818,6 @@
     {
       "slug": "queen-attack",
       "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
-      "core": false,
-      "unlocked_by": "clock",
       "difficulty": 3,
       "topics": [
         "classes"
@@ -1003,8 +826,6 @@
     {
       "slug": "robot-simulator",
       "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
-      "core": false,
-      "unlocked_by": "clock",
       "difficulty": 3,
       "topics": [
         "classes",
@@ -1014,8 +835,6 @@
     {
       "slug": "bank-account",
       "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
-      "core": false,
-      "unlocked_by": "clock",
       "difficulty": 4,
       "topics": [
         "classes",
@@ -1025,8 +844,6 @@
     {
       "slug": "simple-linked-list",
       "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
-      "core": false,
-      "unlocked_by": "clock",
       "difficulty": 4,
       "topics": [
         "classes",
@@ -1036,8 +853,6 @@
     {
       "slug": "error-handling",
       "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 3,
       "topics": [
         "exception_handling"
@@ -1046,8 +861,6 @@
     {
       "slug": "affine-cipher",
       "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 4,
       "topics": [
         "cryptography",
@@ -1058,8 +871,6 @@
     {
       "slug": "isbn-verifier",
       "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 4,
       "topics": [
         "conditionals",
@@ -1071,8 +882,6 @@
     {
       "slug": "twelve-days",
       "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -1082,8 +891,6 @@
     {
       "slug": "word-count",
       "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 4,
       "topics": [
         "dictionaries",
@@ -1094,8 +901,6 @@
     {
       "slug": "yacht",
       "uuid": "f808e80a-8e76-4f3d-840e-31a840c560f2",
-      "core": false,
-      "unlocked_by": "bob",
       "difficulty": 5,
       "topics": [
         "games",
@@ -1106,8 +911,6 @@
     {
       "slug": "dot-dsl",
       "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
-      "core": false,
-      "unlocked_by": "matching-brackets",
       "difficulty": 5,
       "topics": [
         "classes",
@@ -1118,8 +921,6 @@
     {
       "slug": "linked-list",
       "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
-      "core": false,
-      "unlocked_by": "matching-brackets",
       "difficulty": 5,
       "topics": [
         "classes",
@@ -1129,8 +930,6 @@
     {
       "slug": "diamond",
       "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
-      "core": false,
-      "unlocked_by": "matching-brackets",
       "difficulty": 8,
       "topics": [
         "algorithms",
@@ -1140,8 +939,6 @@
     {
       "slug": "grep",
       "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
-      "core": false,
-      "unlocked_by": "spiral-matrix",
       "difficulty": 5,
       "topics": [
         "files",
@@ -1152,8 +949,6 @@
     {
       "slug": "luhn",
       "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
-      "core": false,
-      "unlocked_by": "spiral-matrix",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -1164,8 +959,6 @@
     {
       "slug": "markdown",
       "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
-      "core": false,
-      "unlocked_by": "spiral-matrix",
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -1176,8 +969,6 @@
     {
       "slug": "word-search",
       "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
-      "core": false,
-      "unlocked_by": "spiral-matrix",
       "difficulty": 6,
       "topics": [
         "searching",
@@ -1187,8 +978,6 @@
     {
       "slug": "bowling",
       "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
-      "core": false,
-      "unlocked_by": "tournament",
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -1198,8 +987,6 @@
     {
       "slug": "rest-api",
       "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
-      "core": false,
-      "unlocked_by": "tournament",
       "difficulty": 6,
       "topics": [
         "json",
@@ -1209,8 +996,6 @@
     {
       "slug": "poker",
       "uuid": "d03a9508-336a-4425-8f47-f04317d1ba15",
-      "core": false,
-      "unlocked_by": "tournament",
       "difficulty": 7,
       "topics": [
         "games",
@@ -1221,8 +1006,6 @@
     {
       "slug": "run-length-encoding",
       "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
-      "core": false,
-      "unlocked_by": "variable-length-quantity",
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -1232,8 +1015,6 @@
     {
       "slug": "pig-latin",
       "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
-      "core": false,
-      "unlocked_by": "variable-length-quantity",
       "difficulty": 6,
       "topics": [
         "strings",
@@ -1243,8 +1024,6 @@
     {
       "slug": "transpose",
       "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
-      "core": false,
-      "unlocked_by": "variable-length-quantity",
       "difficulty": 6,
       "topics": [
         "strings",
@@ -1254,8 +1033,6 @@
     {
       "slug": "say",
       "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
-      "core": false,
-      "unlocked_by": "variable-length-quantity",
       "difficulty": 8,
       "topics": [
         "strings",
@@ -1265,8 +1042,6 @@
     {
       "slug": "book-store",
       "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 5,
       "topics": [
         "recursion"
@@ -1275,8 +1050,6 @@
     {
       "slug": "custom-set",
       "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 5,
       "topics": [
         "sets"
@@ -1285,8 +1058,6 @@
     {
       "slug": "nth-prime",
       "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 6,
       "topics": [
         "math"
@@ -1295,8 +1066,6 @@
     {
       "slug": "rail-fence-cipher",
       "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -1307,8 +1076,6 @@
     {
       "slug": "diffie-hellman",
       "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 7,
       "topics": [
         "algorithms",
@@ -1320,8 +1087,6 @@
     {
       "slug": "zebra-puzzle",
       "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
-      "core": false,
-      "unlocked_by": "dominoes",
       "difficulty": 8,
       "topics": [
         "logic"
@@ -1330,8 +1095,6 @@
     {
       "slug": "react",
       "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
-      "core": false,
-      "unlocked_by": "forth",
       "difficulty": 9,
       "topics": [
         "classes",
@@ -1342,8 +1105,6 @@
     {
       "slug": "pov",
       "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
-      "core": false,
-      "unlocked_by": "forth",
       "difficulty": 10,
       "topics": [
         "graphs",
@@ -1354,8 +1115,6 @@
     {
       "slug": "zipper",
       "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
-      "core": false,
-      "unlocked_by": "forth",
       "difficulty": 10,
       "topics": [
         "recursion",
@@ -1366,48 +1125,34 @@
     {
       "slug": "binary",
       "uuid": "cef7deef-54ce-4201-b263-7cd2098533f8",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true,
       "status": "deprecated"
     },
     {
       "slug": "hexadecimal",
       "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true,
       "status": "deprecated"
     },
     {
       "slug": "octal",
       "uuid": "c8555f37-9976-4f52-a5db-6a680ec8d53b",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true,
       "status": "deprecated"
     },
     {
       "slug": "trinary",
       "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 0,
       "topics": null,
-      "deprecated": true,
       "status": "deprecated"
     },
     {
       "slug": "reverse-string",
       "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "strings"
@@ -1416,8 +1161,6 @@
     {
       "slug": "rna-transcription",
       "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
-      "core": false,
-      "unlocked_by": null,
       "difficulty": 1,
       "topics": [
         "strings",

From b561b544b7c74e97d722effa2cdc0e5ecdfc48b8 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:50 +0100
Subject: [PATCH 305/327] [v3] Add name property to practice exercises in
 config.json

---
 config.json | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/config.json b/config.json
index 086d2be760..645058f7fd 100644
--- a/config.json
+++ b/config.json
@@ -24,6 +24,7 @@
   "exercises": [
     {
       "slug": "hello-world",
+      "name": "Hello World",
       "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
       "difficulty": 1,
       "topics": [
@@ -32,6 +33,7 @@
     },
     {
       "slug": "two-fer",
+      "name": "Two Fer",
       "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce",
       "difficulty": 1,
       "topics": [
@@ -41,6 +43,7 @@
     },
     {
       "slug": "leap",
+      "name": "Leap",
       "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
       "difficulty": 1,
       "topics": [
@@ -50,6 +53,7 @@
     },
     {
       "slug": "gigasecond",
+      "name": "Gigasecond",
       "uuid": "b7116dfb-1107-4546-9f95-f15acdb6f6a4",
       "difficulty": 1,
       "topics": [
@@ -58,6 +62,7 @@
     },
     {
       "slug": "resistor-color",
+      "name": "Resistor Color",
       "uuid": "5314dbee-4a0d-4fd6-a98a-36a746ee0d5c",
       "difficulty": 1,
       "topics": [
@@ -66,6 +71,7 @@
     },
     {
       "slug": "space-age",
+      "name": "Space Age",
       "uuid": "612f058b-c6d9-4c97-913a-eeeb59ef61e1",
       "difficulty": 1,
       "topics": [
@@ -74,6 +80,7 @@
     },
     {
       "slug": "high-scores",
+      "name": "High Scores",
       "uuid": "f52d9be9-7044-4001-8678-dcae91a8d7f3",
       "difficulty": 1,
       "topics": [
@@ -82,6 +89,7 @@
     },
     {
       "slug": "hamming",
+      "name": "Hamming",
       "uuid": "05162ee0-38ac-40ad-a591-d70a74b6963a",
       "difficulty": 2,
       "topics": [
@@ -91,6 +99,7 @@
     },
     {
       "slug": "nucleotide-count",
+      "name": "Nucleotide Count",
       "uuid": "caca1c6a-b998-431e-b6af-ca2d47b7708f",
       "difficulty": 2,
       "topics": [
@@ -100,6 +109,7 @@
     },
     {
       "slug": "robot-name",
+      "name": "Robot Name",
       "uuid": "46b8aea8-1528-43cb-a754-495ec2790ce2",
       "difficulty": 3,
       "topics": [
@@ -110,6 +120,7 @@
     },
     {
       "slug": "allergies",
+      "name": "Allergies",
       "uuid": "2ac228d8-7bf0-4946-8352-6541df02c0a2",
       "difficulty": 3,
       "topics": [
@@ -119,6 +130,7 @@
     },
     {
       "slug": "grade-school",
+      "name": "Grade School",
       "uuid": "ec1cc254-8e66-40d0-87bf-971d54c541c4",
       "difficulty": 3,
       "topics": [
@@ -128,6 +140,7 @@
     },
     {
       "slug": "rotational-cipher",
+      "name": "Rotational Cipher",
       "uuid": "8a0a291d-8330-4901-bdbe-f974e163158e",
       "difficulty": 4,
       "topics": [
@@ -138,6 +151,7 @@
     },
     {
       "slug": "circular-buffer",
+      "name": "Circular Buffer",
       "uuid": "657ac368-9b17-4f87-b815-decfe2bc0b5d",
       "difficulty": 4,
       "topics": [
@@ -147,6 +161,7 @@
     },
     {
       "slug": "clock",
+      "name": "Clock",
       "uuid": "83e4cb1e-456f-4c74-ae82-6895f0bd73ae",
       "difficulty": 4,
       "topics": [
@@ -156,6 +171,7 @@
     },
     {
       "slug": "bob",
+      "name": "Bob",
       "uuid": "da00f894-dbc8-485e-adba-a79d5ebee3ad",
       "difficulty": 4,
       "topics": [
@@ -165,6 +181,7 @@
     },
     {
       "slug": "matching-brackets",
+      "name": "Matching Brackets",
       "uuid": "a2070019-e56d-4d48-994b-300411598707",
       "difficulty": 5,
       "topics": [
@@ -174,6 +191,7 @@
     },
     {
       "slug": "spiral-matrix",
+      "name": "Spiral Matrix",
       "uuid": "bae1f3a4-b63d-4efd-921a-133b3d5e379c",
       "difficulty": 5,
       "topics": [
@@ -183,6 +201,7 @@
     },
     {
       "slug": "tournament",
+      "name": "Tournament",
       "uuid": "d9359f25-dc94-496c-adc3-57fe541857fe",
       "difficulty": 6,
       "topics": [
@@ -192,6 +211,7 @@
     },
     {
       "slug": "variable-length-quantity",
+      "name": "Variable Length Quantity",
       "uuid": "4c49ea84-8765-42b0-b4ab-5dead802eeee",
       "difficulty": 7,
       "topics": [
@@ -201,6 +221,7 @@
     },
     {
       "slug": "dominoes",
+      "name": "Dominoes",
       "uuid": "0409f45f-b65e-4404-a9e7-2ef432d834b2",
       "difficulty": 8,
       "topics": [
@@ -210,6 +231,7 @@
     },
     {
       "slug": "forth",
+      "name": "Forth",
       "uuid": "a2ba6202-f6e0-46f4-95e4-5921656f2e1a",
       "difficulty": 10,
       "topics": [
@@ -219,6 +241,7 @@
     },
     {
       "slug": "pangram",
+      "name": "Pangram",
       "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
       "difficulty": 2,
       "topics": [
@@ -227,6 +250,7 @@
     },
     {
       "slug": "isogram",
+      "name": "Isogram",
       "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
       "difficulty": 3,
       "topics": [
@@ -236,6 +260,7 @@
     },
     {
       "slug": "acronym",
+      "name": "Acronym",
       "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
       "difficulty": 4,
       "topics": [
@@ -245,6 +270,7 @@
     },
     {
       "slug": "grains",
+      "name": "Grains",
       "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
       "difficulty": 2,
       "topics": [
@@ -253,6 +279,7 @@
     },
     {
       "slug": "perfect-numbers",
+      "name": "Perfect Numbers",
       "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
       "difficulty": 3,
       "topics": [
@@ -262,6 +289,7 @@
     },
     {
       "slug": "collatz-conjecture",
+      "name": "Collatz Conjecture",
       "uuid": "c4efbf8a-8e76-4700-807d-830a4938f4d0",
       "difficulty": 2,
       "topics": [
@@ -274,6 +302,7 @@
     },
     {
       "slug": "phone-number",
+      "name": "Phone Number",
       "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
       "difficulty": 3,
       "topics": [
@@ -283,6 +312,7 @@
     },
     {
       "slug": "scrabble-score",
+      "name": "Scrabble Score",
       "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
       "difficulty": 3,
       "topics": [
@@ -291,6 +321,7 @@
     },
     {
       "slug": "meetup",
+      "name": "Meetup",
       "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
       "difficulty": 4,
       "topics": [
@@ -299,6 +330,7 @@
     },
     {
       "slug": "difference-of-squares",
+      "name": "Difference Of Squares",
       "uuid": "5554c048-0de3-4a85-b043-7577f429cba4",
       "difficulty": 1,
       "topics": [
@@ -309,6 +341,7 @@
     },
     {
       "slug": "resistor-color-duo",
+      "name": "Resistor Color Duo",
       "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
       "difficulty": 1,
       "topics": [
@@ -317,6 +350,7 @@
     },
     {
       "slug": "resistor-color-trio",
+      "name": "Resistor Color Trio",
       "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
       "difficulty": 1,
       "topics": [
@@ -326,6 +360,7 @@
     },
     {
       "slug": "series",
+      "name": "Series",
       "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
       "difficulty": 1,
       "topics": [
@@ -335,6 +370,7 @@
     },
     {
       "slug": "sum-of-multiples",
+      "name": "Sum Of Multiples",
       "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
       "difficulty": 1,
       "topics": [
@@ -345,6 +381,7 @@
     },
     {
       "slug": "accumulate",
+      "name": "Accumulate",
       "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
       "difficulty": 2,
       "topics": [
@@ -355,6 +392,7 @@
     },
     {
       "slug": "all-your-base",
+      "name": "All Your Base",
       "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
       "difficulty": 4,
       "topics": [
@@ -365,6 +403,7 @@
     },
     {
       "slug": "largest-series-product",
+      "name": "Largest Series Product",
       "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
       "difficulty": 4,
       "topics": [
@@ -376,6 +415,7 @@
     },
     {
       "slug": "pascals-triangle",
+      "name": "Pascals Triangle",
       "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
       "difficulty": 4,
       "topics": [
@@ -386,6 +426,7 @@
     },
     {
       "slug": "prime-factors",
+      "name": "Prime Factors",
       "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
       "difficulty": 4,
       "topics": [
@@ -395,6 +436,7 @@
     },
     {
       "slug": "pythagorean-triplet",
+      "name": "Pythagorean Triplet",
       "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
       "difficulty": 4,
       "topics": [
@@ -405,6 +447,7 @@
     },
     {
       "slug": "armstrong-numbers",
+      "name": "Armstrong Numbers",
       "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
       "difficulty": 2,
       "topics": [
@@ -413,6 +456,7 @@
     },
     {
       "slug": "darts",
+      "name": "Darts",
       "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
       "difficulty": 2,
       "topics": [
@@ -422,6 +466,7 @@
     },
     {
       "slug": "triangle",
+      "name": "Triangle",
       "uuid": "5b1713c7-1597-4e67-ac97-f305b207bc38",
       "difficulty": 3,
       "topics": [
@@ -431,6 +476,7 @@
     },
     {
       "slug": "rational-numbers",
+      "name": "Rational Numbers",
       "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
       "difficulty": 4,
       "topics": [
@@ -439,6 +485,7 @@
     },
     {
       "slug": "complex-numbers",
+      "name": "Complex Numbers",
       "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
       "difficulty": 6,
       "topics": [
@@ -448,6 +495,7 @@
     },
     {
       "slug": "raindrops",
+      "name": "Raindrops",
       "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
       "difficulty": 2,
       "topics": [
@@ -457,6 +505,7 @@
     },
     {
       "slug": "beer-song",
+      "name": "Beer Song",
       "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
       "difficulty": 3,
       "topics": [
@@ -466,6 +515,7 @@
     },
     {
       "slug": "proverb",
+      "name": "Proverb",
       "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
       "difficulty": 3,
       "topics": [
@@ -475,6 +525,7 @@
     },
     {
       "slug": "strain",
+      "name": "Strain",
       "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
       "difficulty": 3,
       "topics": [
@@ -484,6 +535,7 @@
     },
     {
       "slug": "house",
+      "name": "House",
       "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
       "difficulty": 4,
       "topics": [
@@ -493,6 +545,7 @@
     },
     {
       "slug": "protein-translation",
+      "name": "Protein Translation",
       "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
       "difficulty": 3,
       "topics": [
@@ -503,6 +556,7 @@
     },
     {
       "slug": "roman-numerals",
+      "name": "Roman Numerals",
       "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
       "difficulty": 5,
       "topics": [
@@ -512,6 +566,7 @@
     },
     {
       "slug": "simple-cipher",
+      "name": "Simple Cipher",
       "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
       "difficulty": 5,
       "topics": [
@@ -522,6 +577,7 @@
     },
     {
       "slug": "etl",
+      "name": "Etl",
       "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
       "difficulty": 2,
       "topics": [
@@ -532,6 +588,7 @@
     },
     {
       "slug": "parallel-letter-frequency",
+      "name": "Parallel Letter Frequency",
       "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
       "difficulty": 5,
       "topics": [
@@ -542,6 +599,7 @@
     },
     {
       "slug": "alphametics",
+      "name": "Alphametics",
       "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
       "difficulty": 10,
       "topics": [
@@ -551,6 +609,7 @@
     },
     {
       "slug": "sieve",
+      "name": "Sieve",
       "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
       "difficulty": 3,
       "topics": [
@@ -560,6 +619,7 @@
     },
     {
       "slug": "anagram",
+      "name": "Anagram",
       "uuid": "790216d1-4fd9-4a9b-94f8-e1e07a18c2b7",
       "difficulty": 4,
       "topics": [
@@ -569,6 +629,7 @@
     },
     {
       "slug": "binary-search",
+      "name": "Binary Search",
       "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
       "difficulty": 3,
       "topics": [
@@ -578,6 +639,7 @@
     },
     {
       "slug": "kindergarten-garden",
+      "name": "Kindergarten Garden",
       "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
       "difficulty": 3,
       "topics": [
@@ -587,6 +649,7 @@
     },
     {
       "slug": "secret-handshake",
+      "name": "Secret Handshake",
       "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
       "difficulty": 3,
       "topics": [
@@ -596,6 +659,7 @@
     },
     {
       "slug": "matrix",
+      "name": "Matrix",
       "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
       "difficulty": 4,
       "topics": [
@@ -605,6 +669,7 @@
     },
     {
       "slug": "crypto-square",
+      "name": "Crypto Square",
       "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
       "difficulty": 5,
       "topics": [
@@ -615,6 +680,7 @@
     },
     {
       "slug": "food-chain",
+      "name": "Food Chain",
       "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
       "difficulty": 5,
       "topics": [
@@ -624,6 +690,7 @@
     },
     {
       "slug": "minesweeper",
+      "name": "Minesweeper",
       "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
       "difficulty": 5,
       "topics": [
@@ -633,6 +700,7 @@
     },
     {
       "slug": "scale-generator",
+      "name": "Scale Generator",
       "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
       "difficulty": 5,
       "topics": [
@@ -642,6 +710,7 @@
     },
     {
       "slug": "tree-building",
+      "name": "Tree Building",
       "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
       "difficulty": 5,
       "topics": [
@@ -651,6 +720,7 @@
     },
     {
       "slug": "change",
+      "name": "Change",
       "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
       "difficulty": 6,
       "topics": [
@@ -660,6 +730,7 @@
     },
     {
       "slug": "rectangles",
+      "name": "Rectangles",
       "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
       "difficulty": 7,
       "topics": [
@@ -669,6 +740,7 @@
     },
     {
       "slug": "wordy",
+      "name": "Wordy",
       "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
       "difficulty": 7,
       "topics": [
@@ -679,6 +751,7 @@
     },
     {
       "slug": "connect",
+      "name": "Connect",
       "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
       "difficulty": 8,
       "topics": [
@@ -688,6 +761,7 @@
     },
     {
       "slug": "sgf-parsing",
+      "name": "Sgf Parsing",
       "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
       "difficulty": 9,
       "topics": [
@@ -697,6 +771,7 @@
     },
     {
       "slug": "atbash-cipher",
+      "name": "Atbash Cipher",
       "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
       "difficulty": 5,
       "topics": [
@@ -707,6 +782,7 @@
     },
     {
       "slug": "binary-search-tree",
+      "name": "Binary Search Tree",
       "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
       "difficulty": 5,
       "topics": [
@@ -716,6 +792,7 @@
     },
     {
       "slug": "flatten-array",
+      "name": "Flatten Array",
       "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
       "difficulty": 5,
       "topics": [
@@ -725,6 +802,7 @@
     },
     {
       "slug": "list-ops",
+      "name": "List Ops",
       "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
       "difficulty": 5,
       "topics": [
@@ -734,6 +812,7 @@
     },
     {
       "slug": "sublist",
+      "name": "Sublist",
       "uuid": "89d3b074-190f-4520-8f87-cde6368fc58e",
       "difficulty": 5,
       "topics": [
@@ -742,6 +821,7 @@
     },
     {
       "slug": "ledger",
+      "name": "Ledger",
       "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
       "difficulty": 5,
       "topics": [
@@ -752,6 +832,7 @@
     },
     {
       "slug": "ocr-numbers",
+      "name": "Ocr Numbers",
       "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
       "difficulty": 5,
       "topics": [
@@ -761,6 +842,7 @@
     },
     {
       "slug": "saddle-points",
+      "name": "Saddle Points",
       "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
       "difficulty": 4,
       "topics": [
@@ -771,6 +853,7 @@
     },
     {
       "slug": "palindrome-products",
+      "name": "Palindrome Products",
       "uuid": "165b8599-726d-43dd-8511-1401525810de",
       "difficulty": 6,
       "topics": [
@@ -782,6 +865,7 @@
     },
     {
       "slug": "hangman",
+      "name": "Hangman",
       "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
       "difficulty": 8,
       "topics": [
@@ -791,6 +875,7 @@
     },
     {
       "slug": "two-bucket",
+      "name": "Two Bucket",
       "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
       "difficulty": 8,
       "topics": [
@@ -799,6 +884,7 @@
     },
     {
       "slug": "go-counting",
+      "name": "Go Counting",
       "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
       "difficulty": 9,
       "topics": [
@@ -809,6 +895,7 @@
     },
     {
       "slug": "dnd-character",
+      "name": "Dnd Character",
       "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
       "difficulty": 3,
       "topics": [
@@ -817,6 +904,7 @@
     },
     {
       "slug": "queen-attack",
+      "name": "Queen Attack",
       "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
       "difficulty": 3,
       "topics": [
@@ -825,6 +913,7 @@
     },
     {
       "slug": "robot-simulator",
+      "name": "Robot Simulator",
       "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
       "difficulty": 3,
       "topics": [
@@ -834,6 +923,7 @@
     },
     {
       "slug": "bank-account",
+      "name": "Bank Account",
       "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
       "difficulty": 4,
       "topics": [
@@ -843,6 +933,7 @@
     },
     {
       "slug": "simple-linked-list",
+      "name": "Simple Linked List",
       "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
       "difficulty": 4,
       "topics": [
@@ -852,6 +943,7 @@
     },
     {
       "slug": "error-handling",
+      "name": "Error Handling",
       "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
       "difficulty": 3,
       "topics": [
@@ -860,6 +952,7 @@
     },
     {
       "slug": "affine-cipher",
+      "name": "Affine Cipher",
       "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
       "difficulty": 4,
       "topics": [
@@ -870,6 +963,7 @@
     },
     {
       "slug": "isbn-verifier",
+      "name": "Isbn Verifier",
       "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
       "difficulty": 4,
       "topics": [
@@ -881,6 +975,7 @@
     },
     {
       "slug": "twelve-days",
+      "name": "Twelve Days",
       "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
       "difficulty": 4,
       "topics": [
@@ -890,6 +985,7 @@
     },
     {
       "slug": "word-count",
+      "name": "Word Count",
       "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
       "difficulty": 4,
       "topics": [
@@ -900,6 +996,7 @@
     },
     {
       "slug": "yacht",
+      "name": "Yacht",
       "uuid": "f808e80a-8e76-4f3d-840e-31a840c560f2",
       "difficulty": 5,
       "topics": [
@@ -910,6 +1007,7 @@
     },
     {
       "slug": "dot-dsl",
+      "name": "Dot Dsl",
       "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
       "difficulty": 5,
       "topics": [
@@ -920,6 +1018,7 @@
     },
     {
       "slug": "linked-list",
+      "name": "Linked List",
       "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
       "difficulty": 5,
       "topics": [
@@ -929,6 +1028,7 @@
     },
     {
       "slug": "diamond",
+      "name": "Diamond",
       "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
       "difficulty": 8,
       "topics": [
@@ -938,6 +1038,7 @@
     },
     {
       "slug": "grep",
+      "name": "Grep",
       "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
       "difficulty": 5,
       "topics": [
@@ -948,6 +1049,7 @@
     },
     {
       "slug": "luhn",
+      "name": "Luhn",
       "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
       "difficulty": 5,
       "topics": [
@@ -958,6 +1060,7 @@
     },
     {
       "slug": "markdown",
+      "name": "Markdown",
       "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
       "difficulty": 5,
       "topics": [
@@ -968,6 +1071,7 @@
     },
     {
       "slug": "word-search",
+      "name": "Word Search",
       "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
       "difficulty": 6,
       "topics": [
@@ -977,6 +1081,7 @@
     },
     {
       "slug": "bowling",
+      "name": "Bowling",
       "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
       "difficulty": 6,
       "topics": [
@@ -986,6 +1091,7 @@
     },
     {
       "slug": "rest-api",
+      "name": "Rest Api",
       "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
       "difficulty": 6,
       "topics": [
@@ -995,6 +1101,7 @@
     },
     {
       "slug": "poker",
+      "name": "Poker",
       "uuid": "d03a9508-336a-4425-8f47-f04317d1ba15",
       "difficulty": 7,
       "topics": [
@@ -1005,6 +1112,7 @@
     },
     {
       "slug": "run-length-encoding",
+      "name": "Run Length Encoding",
       "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
       "difficulty": 5,
       "topics": [
@@ -1014,6 +1122,7 @@
     },
     {
       "slug": "pig-latin",
+      "name": "Pig Latin",
       "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
       "difficulty": 6,
       "topics": [
@@ -1023,6 +1132,7 @@
     },
     {
       "slug": "transpose",
+      "name": "Transpose",
       "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
       "difficulty": 6,
       "topics": [
@@ -1032,6 +1142,7 @@
     },
     {
       "slug": "say",
+      "name": "Say",
       "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
       "difficulty": 8,
       "topics": [
@@ -1041,6 +1152,7 @@
     },
     {
       "slug": "book-store",
+      "name": "Book Store",
       "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
       "difficulty": 5,
       "topics": [
@@ -1049,6 +1161,7 @@
     },
     {
       "slug": "custom-set",
+      "name": "Custom Set",
       "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
       "difficulty": 5,
       "topics": [
@@ -1057,6 +1170,7 @@
     },
     {
       "slug": "nth-prime",
+      "name": "Nth Prime",
       "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
       "difficulty": 6,
       "topics": [
@@ -1065,6 +1179,7 @@
     },
     {
       "slug": "rail-fence-cipher",
+      "name": "Rail Fence Cipher",
       "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
       "difficulty": 6,
       "topics": [
@@ -1075,6 +1190,7 @@
     },
     {
       "slug": "diffie-hellman",
+      "name": "Diffie Hellman",
       "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
       "difficulty": 7,
       "topics": [
@@ -1086,6 +1202,7 @@
     },
     {
       "slug": "zebra-puzzle",
+      "name": "Zebra Puzzle",
       "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
       "difficulty": 8,
       "topics": [
@@ -1094,6 +1211,7 @@
     },
     {
       "slug": "react",
+      "name": "React",
       "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
       "difficulty": 9,
       "topics": [
@@ -1104,6 +1222,7 @@
     },
     {
       "slug": "pov",
+      "name": "Pov",
       "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
       "difficulty": 10,
       "topics": [
@@ -1114,6 +1233,7 @@
     },
     {
       "slug": "zipper",
+      "name": "Zipper",
       "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
       "difficulty": 10,
       "topics": [
@@ -1124,6 +1244,7 @@
     },
     {
       "slug": "binary",
+      "name": "Binary",
       "uuid": "cef7deef-54ce-4201-b263-7cd2098533f8",
       "difficulty": 0,
       "topics": null,
@@ -1131,6 +1252,7 @@
     },
     {
       "slug": "hexadecimal",
+      "name": "Hexadecimal",
       "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
       "difficulty": 0,
       "topics": null,
@@ -1138,6 +1260,7 @@
     },
     {
       "slug": "octal",
+      "name": "Octal",
       "uuid": "c8555f37-9976-4f52-a5db-6a680ec8d53b",
       "difficulty": 0,
       "topics": null,
@@ -1145,6 +1268,7 @@
     },
     {
       "slug": "trinary",
+      "name": "Trinary",
       "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
       "difficulty": 0,
       "topics": null,
@@ -1152,6 +1276,7 @@
     },
     {
       "slug": "reverse-string",
+      "name": "Reverse String",
       "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
       "difficulty": 1,
       "topics": [
@@ -1160,6 +1285,7 @@
     },
     {
       "slug": "rna-transcription",
+      "name": "Rna Transcription",
       "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
       "difficulty": 1,
       "topics": [

From 67373dd00852c66d286192cfae826ea3453f4da6 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:50 +0100
Subject: [PATCH 306/327] [v3] Add (empty) prerequisites property to practice
 exercises in config.json

---
 config.json | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/config.json b/config.json
index 645058f7fd..a9b0da5597 100644
--- a/config.json
+++ b/config.json
@@ -26,6 +26,7 @@
       "slug": "hello-world",
       "name": "Hello World",
       "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "strings"
@@ -35,6 +36,7 @@
       "slug": "two-fer",
       "name": "Two Fer",
       "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "optional_values",
@@ -45,6 +47,7 @@
       "slug": "leap",
       "name": "Leap",
       "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "conditionals",
@@ -55,6 +58,7 @@
       "slug": "gigasecond",
       "name": "Gigasecond",
       "uuid": "b7116dfb-1107-4546-9f95-f15acdb6f6a4",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "dates"
@@ -64,6 +68,7 @@
       "slug": "resistor-color",
       "name": "Resistor Color",
       "uuid": "5314dbee-4a0d-4fd6-a98a-36a746ee0d5c",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "arrays"
@@ -73,6 +78,7 @@
       "slug": "space-age",
       "name": "Space Age",
       "uuid": "612f058b-c6d9-4c97-913a-eeeb59ef61e1",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "floating_point_numbers"
@@ -82,6 +88,7 @@
       "slug": "high-scores",
       "name": "High Scores",
       "uuid": "f52d9be9-7044-4001-8678-dcae91a8d7f3",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "lists"
@@ -91,6 +98,7 @@
       "slug": "hamming",
       "name": "Hamming",
       "uuid": "05162ee0-38ac-40ad-a591-d70a74b6963a",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "filtering",
@@ -101,6 +109,7 @@
       "slug": "nucleotide-count",
       "name": "Nucleotide Count",
       "uuid": "caca1c6a-b998-431e-b6af-ca2d47b7708f",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "dictionaries",
@@ -111,6 +120,7 @@
       "slug": "robot-name",
       "name": "Robot Name",
       "uuid": "46b8aea8-1528-43cb-a754-495ec2790ce2",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "classes",
@@ -122,6 +132,7 @@
       "slug": "allergies",
       "name": "Allergies",
       "uuid": "2ac228d8-7bf0-4946-8352-6541df02c0a2",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "bitwise_operations",
@@ -132,6 +143,7 @@
       "slug": "grade-school",
       "name": "Grade School",
       "uuid": "ec1cc254-8e66-40d0-87bf-971d54c541c4",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "lists",
@@ -142,6 +154,7 @@
       "slug": "rotational-cipher",
       "name": "Rotational Cipher",
       "uuid": "8a0a291d-8330-4901-bdbe-f974e163158e",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -153,6 +166,7 @@
       "slug": "circular-buffer",
       "name": "Circular Buffer",
       "uuid": "657ac368-9b17-4f87-b815-decfe2bc0b5d",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "classes",
@@ -163,6 +177,7 @@
       "slug": "clock",
       "name": "Clock",
       "uuid": "83e4cb1e-456f-4c74-ae82-6895f0bd73ae",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "classes",
@@ -173,6 +188,7 @@
       "slug": "bob",
       "name": "Bob",
       "uuid": "da00f894-dbc8-485e-adba-a79d5ebee3ad",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "conditionals",
@@ -183,6 +199,7 @@
       "slug": "matching-brackets",
       "name": "Matching Brackets",
       "uuid": "a2070019-e56d-4d48-994b-300411598707",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -193,6 +210,7 @@
       "slug": "spiral-matrix",
       "name": "Spiral Matrix",
       "uuid": "bae1f3a4-b63d-4efd-921a-133b3d5e379c",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -203,6 +221,7 @@
       "slug": "tournament",
       "name": "Tournament",
       "uuid": "d9359f25-dc94-496c-adc3-57fe541857fe",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "parsing",
@@ -213,6 +232,7 @@
       "slug": "variable-length-quantity",
       "name": "Variable Length Quantity",
       "uuid": "4c49ea84-8765-42b0-b4ab-5dead802eeee",
+      "prerequisites": [],
       "difficulty": 7,
       "topics": [
         "algorithms",
@@ -223,6 +243,7 @@
       "slug": "dominoes",
       "name": "Dominoes",
       "uuid": "0409f45f-b65e-4404-a9e7-2ef432d834b2",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "arrays",
@@ -233,6 +254,7 @@
       "slug": "forth",
       "name": "Forth",
       "uuid": "a2ba6202-f6e0-46f4-95e4-5921656f2e1a",
+      "prerequisites": [],
       "difficulty": 10,
       "topics": [
         "parsing",
@@ -243,6 +265,7 @@
       "slug": "pangram",
       "name": "Pangram",
       "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "strings"
@@ -252,6 +275,7 @@
       "slug": "isogram",
       "name": "Isogram",
       "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -262,6 +286,7 @@
       "slug": "acronym",
       "name": "Acronym",
       "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "strings",
@@ -272,6 +297,7 @@
       "slug": "grains",
       "name": "Grains",
       "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "integers"
@@ -281,6 +307,7 @@
       "slug": "perfect-numbers",
       "name": "Perfect Numbers",
       "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "integers",
@@ -291,6 +318,7 @@
       "slug": "collatz-conjecture",
       "name": "Collatz Conjecture",
       "uuid": "c4efbf8a-8e76-4700-807d-830a4938f4d0",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "algorithms",
@@ -304,6 +332,7 @@
       "slug": "phone-number",
       "name": "Phone Number",
       "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "parsing",
@@ -314,6 +343,7 @@
       "slug": "scrabble-score",
       "name": "Scrabble Score",
       "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "transforming"
@@ -323,6 +353,7 @@
       "slug": "meetup",
       "name": "Meetup",
       "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "dates"
@@ -332,6 +363,7 @@
       "slug": "difference-of-squares",
       "name": "Difference Of Squares",
       "uuid": "5554c048-0de3-4a85-b043-7577f429cba4",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "integers",
@@ -343,6 +375,7 @@
       "slug": "resistor-color-duo",
       "name": "Resistor Color Duo",
       "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "arrays"
@@ -352,6 +385,7 @@
       "slug": "resistor-color-trio",
       "name": "Resistor Color Trio",
       "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -362,6 +396,7 @@
       "slug": "series",
       "name": "Series",
       "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -372,6 +407,7 @@
       "slug": "sum-of-multiples",
       "name": "Sum Of Multiples",
       "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "arrays",
@@ -383,6 +419,7 @@
       "slug": "accumulate",
       "name": "Accumulate",
       "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "extension_methods",
@@ -394,6 +431,7 @@
       "slug": "all-your-base",
       "name": "All Your Base",
       "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "integers",
@@ -405,6 +443,7 @@
       "slug": "largest-series-product",
       "name": "Largest Series Product",
       "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "integers",
@@ -417,6 +456,7 @@
       "slug": "pascals-triangle",
       "name": "Pascals Triangle",
       "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "arrays",
@@ -428,6 +468,7 @@
       "slug": "prime-factors",
       "name": "Prime Factors",
       "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "integers",
@@ -438,6 +479,7 @@
       "slug": "pythagorean-triplet",
       "name": "Pythagorean Triplet",
       "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "integers",
@@ -449,6 +491,7 @@
       "slug": "armstrong-numbers",
       "name": "Armstrong Numbers",
       "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "math"
@@ -458,6 +501,7 @@
       "slug": "darts",
       "name": "Darts",
       "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "floating_point_numbers",
@@ -468,6 +512,7 @@
       "slug": "triangle",
       "name": "Triangle",
       "uuid": "5b1713c7-1597-4e67-ac97-f305b207bc38",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "enumerations",
@@ -478,6 +523,7 @@
       "slug": "rational-numbers",
       "name": "Rational Numbers",
       "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "math"
@@ -487,6 +533,7 @@
       "slug": "complex-numbers",
       "name": "Complex Numbers",
       "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "math",
@@ -497,6 +544,7 @@
       "slug": "raindrops",
       "name": "Raindrops",
       "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "filtering",
@@ -507,6 +555,7 @@
       "slug": "beer-song",
       "name": "Beer Song",
       "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "algorithms",
@@ -517,6 +566,7 @@
       "slug": "proverb",
       "name": "Proverb",
       "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "algorithms",
@@ -527,6 +577,7 @@
       "slug": "strain",
       "name": "Strain",
       "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -537,6 +588,7 @@
       "slug": "house",
       "name": "House",
       "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -547,6 +599,7 @@
       "slug": "protein-translation",
       "name": "Protein Translation",
       "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "lists",
@@ -558,6 +611,7 @@
       "slug": "roman-numerals",
       "name": "Roman Numerals",
       "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "loops",
@@ -568,6 +622,7 @@
       "slug": "simple-cipher",
       "name": "Simple Cipher",
       "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -579,6 +634,7 @@
       "slug": "etl",
       "name": "Etl",
       "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
+      "prerequisites": [],
       "difficulty": 2,
       "topics": [
         "dictionaries",
@@ -590,6 +646,7 @@
       "slug": "parallel-letter-frequency",
       "name": "Parallel Letter Frequency",
       "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "dictionaries",
@@ -601,6 +658,7 @@
       "slug": "alphametics",
       "name": "Alphametics",
       "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
+      "prerequisites": [],
       "difficulty": 10,
       "topics": [
         "dictionaries",
@@ -611,6 +669,7 @@
       "slug": "sieve",
       "name": "Sieve",
       "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "filtering",
@@ -621,6 +680,7 @@
       "slug": "anagram",
       "name": "Anagram",
       "uuid": "790216d1-4fd9-4a9b-94f8-e1e07a18c2b7",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "filtering",
@@ -631,6 +691,7 @@
       "slug": "binary-search",
       "name": "Binary Search",
       "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "arrays",
@@ -641,6 +702,7 @@
       "slug": "kindergarten-garden",
       "name": "Kindergarten Garden",
       "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "enumerations",
@@ -651,6 +713,7 @@
       "slug": "secret-handshake",
       "name": "Secret Handshake",
       "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "arrays",
@@ -661,6 +724,7 @@
       "slug": "matrix",
       "name": "Matrix",
       "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "matrices",
@@ -671,6 +735,7 @@
       "slug": "crypto-square",
       "name": "Crypto Square",
       "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -682,6 +747,7 @@
       "slug": "food-chain",
       "name": "Food Chain",
       "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -692,6 +758,7 @@
       "slug": "minesweeper",
       "name": "Minesweeper",
       "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -702,6 +769,7 @@
       "slug": "scale-generator",
       "name": "Scale Generator",
       "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -712,6 +780,7 @@
       "slug": "tree-building",
       "name": "Tree Building",
       "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "refactoring",
@@ -722,6 +791,7 @@
       "slug": "change",
       "name": "Change",
       "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "arrays",
@@ -732,6 +802,7 @@
       "slug": "rectangles",
       "name": "Rectangles",
       "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
+      "prerequisites": [],
       "difficulty": 7,
       "topics": [
         "parsing",
@@ -742,6 +813,7 @@
       "slug": "wordy",
       "name": "Wordy",
       "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
+      "prerequisites": [],
       "difficulty": 7,
       "topics": [
         "parsing",
@@ -753,6 +825,7 @@
       "slug": "connect",
       "name": "Connect",
       "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "parsing",
@@ -763,6 +836,7 @@
       "slug": "sgf-parsing",
       "name": "Sgf Parsing",
       "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
+      "prerequisites": [],
       "difficulty": 9,
       "topics": [
         "parsing",
@@ -773,6 +847,7 @@
       "slug": "atbash-cipher",
       "name": "Atbash Cipher",
       "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -784,6 +859,7 @@
       "slug": "binary-search-tree",
       "name": "Binary Search Tree",
       "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "searching",
@@ -794,6 +870,7 @@
       "slug": "flatten-array",
       "name": "Flatten Array",
       "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "lists",
@@ -804,6 +881,7 @@
       "slug": "list-ops",
       "name": "List Ops",
       "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "lists",
@@ -814,6 +892,7 @@
       "slug": "sublist",
       "name": "Sublist",
       "uuid": "89d3b074-190f-4520-8f87-cde6368fc58e",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "lists"
@@ -823,6 +902,7 @@
       "slug": "ledger",
       "name": "Ledger",
       "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "globalization",
@@ -834,6 +914,7 @@
       "slug": "ocr-numbers",
       "name": "Ocr Numbers",
       "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -844,6 +925,7 @@
       "slug": "saddle-points",
       "name": "Saddle Points",
       "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "arrays",
@@ -855,6 +937,7 @@
       "slug": "palindrome-products",
       "name": "Palindrome Products",
       "uuid": "165b8599-726d-43dd-8511-1401525810de",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -867,6 +950,7 @@
       "slug": "hangman",
       "name": "Hangman",
       "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "events",
@@ -877,6 +961,7 @@
       "slug": "two-bucket",
       "name": "Two Bucket",
       "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "logic"
@@ -886,6 +971,7 @@
       "slug": "go-counting",
       "name": "Go Counting",
       "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
+      "prerequisites": [],
       "difficulty": 9,
       "topics": [
         "optional_values",
@@ -897,6 +983,7 @@
       "slug": "dnd-character",
       "name": "Dnd Character",
       "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "randomness"
@@ -906,6 +993,7 @@
       "slug": "queen-attack",
       "name": "Queen Attack",
       "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "classes"
@@ -915,6 +1003,7 @@
       "slug": "robot-simulator",
       "name": "Robot Simulator",
       "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "classes",
@@ -925,6 +1014,7 @@
       "slug": "bank-account",
       "name": "Bank Account",
       "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "classes",
@@ -935,6 +1025,7 @@
       "slug": "simple-linked-list",
       "name": "Simple Linked List",
       "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "classes",
@@ -945,6 +1036,7 @@
       "slug": "error-handling",
       "name": "Error Handling",
       "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
+      "prerequisites": [],
       "difficulty": 3,
       "topics": [
         "exception_handling"
@@ -954,6 +1046,7 @@
       "slug": "affine-cipher",
       "name": "Affine Cipher",
       "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "cryptography",
@@ -965,6 +1058,7 @@
       "slug": "isbn-verifier",
       "name": "Isbn Verifier",
       "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "conditionals",
@@ -977,6 +1071,7 @@
       "slug": "twelve-days",
       "name": "Twelve Days",
       "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "algorithms",
@@ -987,6 +1082,7 @@
       "slug": "word-count",
       "name": "Word Count",
       "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
+      "prerequisites": [],
       "difficulty": 4,
       "topics": [
         "dictionaries",
@@ -998,6 +1094,7 @@
       "slug": "yacht",
       "name": "Yacht",
       "uuid": "f808e80a-8e76-4f3d-840e-31a840c560f2",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "games",
@@ -1009,6 +1106,7 @@
       "slug": "dot-dsl",
       "name": "Dot Dsl",
       "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "classes",
@@ -1020,6 +1118,7 @@
       "slug": "linked-list",
       "name": "Linked List",
       "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "classes",
@@ -1030,6 +1129,7 @@
       "slug": "diamond",
       "name": "Diamond",
       "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "algorithms",
@@ -1040,6 +1140,7 @@
       "slug": "grep",
       "name": "Grep",
       "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "files",
@@ -1051,6 +1152,7 @@
       "slug": "luhn",
       "name": "Luhn",
       "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -1062,6 +1164,7 @@
       "slug": "markdown",
       "name": "Markdown",
       "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "parsing",
@@ -1073,6 +1176,7 @@
       "slug": "word-search",
       "name": "Word Search",
       "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "searching",
@@ -1083,6 +1187,7 @@
       "slug": "bowling",
       "name": "Bowling",
       "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -1093,6 +1198,7 @@
       "slug": "rest-api",
       "name": "Rest Api",
       "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "json",
@@ -1103,6 +1209,7 @@
       "slug": "poker",
       "name": "Poker",
       "uuid": "d03a9508-336a-4425-8f47-f04317d1ba15",
+      "prerequisites": [],
       "difficulty": 7,
       "topics": [
         "games",
@@ -1114,6 +1221,7 @@
       "slug": "run-length-encoding",
       "name": "Run Length Encoding",
       "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "algorithms",
@@ -1124,6 +1232,7 @@
       "slug": "pig-latin",
       "name": "Pig Latin",
       "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "strings",
@@ -1134,6 +1243,7 @@
       "slug": "transpose",
       "name": "Transpose",
       "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "strings",
@@ -1144,6 +1254,7 @@
       "slug": "say",
       "name": "Say",
       "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "strings",
@@ -1154,6 +1265,7 @@
       "slug": "book-store",
       "name": "Book Store",
       "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "recursion"
@@ -1163,6 +1275,7 @@
       "slug": "custom-set",
       "name": "Custom Set",
       "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
+      "prerequisites": [],
       "difficulty": 5,
       "topics": [
         "sets"
@@ -1172,6 +1285,7 @@
       "slug": "nth-prime",
       "name": "Nth Prime",
       "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "math"
@@ -1181,6 +1295,7 @@
       "slug": "rail-fence-cipher",
       "name": "Rail Fence Cipher",
       "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
+      "prerequisites": [],
       "difficulty": 6,
       "topics": [
         "algorithms",
@@ -1192,6 +1307,7 @@
       "slug": "diffie-hellman",
       "name": "Diffie Hellman",
       "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
+      "prerequisites": [],
       "difficulty": 7,
       "topics": [
         "algorithms",
@@ -1204,6 +1320,7 @@
       "slug": "zebra-puzzle",
       "name": "Zebra Puzzle",
       "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
+      "prerequisites": [],
       "difficulty": 8,
       "topics": [
         "logic"
@@ -1213,6 +1330,7 @@
       "slug": "react",
       "name": "React",
       "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
+      "prerequisites": [],
       "difficulty": 9,
       "topics": [
         "classes",
@@ -1224,6 +1342,7 @@
       "slug": "pov",
       "name": "Pov",
       "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
+      "prerequisites": [],
       "difficulty": 10,
       "topics": [
         "graphs",
@@ -1235,6 +1354,7 @@
       "slug": "zipper",
       "name": "Zipper",
       "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
+      "prerequisites": [],
       "difficulty": 10,
       "topics": [
         "recursion",
@@ -1246,6 +1366,7 @@
       "slug": "binary",
       "name": "Binary",
       "uuid": "cef7deef-54ce-4201-b263-7cd2098533f8",
+      "prerequisites": [],
       "difficulty": 0,
       "topics": null,
       "status": "deprecated"
@@ -1254,6 +1375,7 @@
       "slug": "hexadecimal",
       "name": "Hexadecimal",
       "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
+      "prerequisites": [],
       "difficulty": 0,
       "topics": null,
       "status": "deprecated"
@@ -1262,6 +1384,7 @@
       "slug": "octal",
       "name": "Octal",
       "uuid": "c8555f37-9976-4f52-a5db-6a680ec8d53b",
+      "prerequisites": [],
       "difficulty": 0,
       "topics": null,
       "status": "deprecated"
@@ -1270,6 +1393,7 @@
       "slug": "trinary",
       "name": "Trinary",
       "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
+      "prerequisites": [],
       "difficulty": 0,
       "topics": null,
       "status": "deprecated"
@@ -1278,6 +1402,7 @@
       "slug": "reverse-string",
       "name": "Reverse String",
       "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "strings"
@@ -1287,6 +1412,7 @@
       "slug": "rna-transcription",
       "name": "Rna Transcription",
       "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
+      "prerequisites": [],
       "difficulty": 1,
       "topics": [
         "strings",

From 79f2e8ce0093783b67989dc12c4a6973b3e72420 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:50 +0100
Subject: [PATCH 307/327] [v3] Move exercises to practice exercises property in
 config.json

---
 config.json | 2800 ++++++++++++++++++++++++++-------------------------
 1 file changed, 1401 insertions(+), 1399 deletions(-)

diff --git a/config.json b/config.json
index a9b0da5597..a8f93e3984 100644
--- a/config.json
+++ b/config.json
@@ -21,1403 +21,1405 @@
     "point-mutations",
     "counter"
   ],
-  "exercises": [
-    {
-      "slug": "hello-world",
-      "name": "Hello World",
-      "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "strings"
-      ]
-    },
-    {
-      "slug": "two-fer",
-      "name": "Two Fer",
-      "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "optional_values",
-        "strings"
-      ]
-    },
-    {
-      "slug": "leap",
-      "name": "Leap",
-      "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "conditionals",
-        "integers"
-      ]
-    },
-    {
-      "slug": "gigasecond",
-      "name": "Gigasecond",
-      "uuid": "b7116dfb-1107-4546-9f95-f15acdb6f6a4",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "dates"
-      ]
-    },
-    {
-      "slug": "resistor-color",
-      "name": "Resistor Color",
-      "uuid": "5314dbee-4a0d-4fd6-a98a-36a746ee0d5c",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "arrays"
-      ]
-    },
-    {
-      "slug": "space-age",
-      "name": "Space Age",
-      "uuid": "612f058b-c6d9-4c97-913a-eeeb59ef61e1",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "floating_point_numbers"
-      ]
-    },
-    {
-      "slug": "high-scores",
-      "name": "High Scores",
-      "uuid": "f52d9be9-7044-4001-8678-dcae91a8d7f3",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "lists"
-      ]
-    },
-    {
-      "slug": "hamming",
-      "name": "Hamming",
-      "uuid": "05162ee0-38ac-40ad-a591-d70a74b6963a",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "filtering",
-        "strings"
-      ]
-    },
-    {
-      "slug": "nucleotide-count",
-      "name": "Nucleotide Count",
-      "uuid": "caca1c6a-b998-431e-b6af-ca2d47b7708f",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "dictionaries",
-        "strings"
-      ]
-    },
-    {
-      "slug": "robot-name",
-      "name": "Robot Name",
-      "uuid": "46b8aea8-1528-43cb-a754-495ec2790ce2",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "classes",
-        "randomness",
-        "strings"
-      ]
-    },
-    {
-      "slug": "allergies",
-      "name": "Allergies",
-      "uuid": "2ac228d8-7bf0-4946-8352-6541df02c0a2",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "bitwise_operations",
-        "filtering"
-      ]
-    },
-    {
-      "slug": "grade-school",
-      "name": "Grade School",
-      "uuid": "ec1cc254-8e66-40d0-87bf-971d54c541c4",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "lists",
-        "sorting"
-      ]
-    },
-    {
-      "slug": "rotational-cipher",
-      "name": "Rotational Cipher",
-      "uuid": "8a0a291d-8330-4901-bdbe-f974e163158e",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "circular-buffer",
-      "name": "Circular Buffer",
-      "uuid": "657ac368-9b17-4f87-b815-decfe2bc0b5d",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "classes",
-        "queues"
-      ]
-    },
-    {
-      "slug": "clock",
-      "name": "Clock",
-      "uuid": "83e4cb1e-456f-4c74-ae82-6895f0bd73ae",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "classes",
-        "equality"
-      ]
-    },
-    {
-      "slug": "bob",
-      "name": "Bob",
-      "uuid": "da00f894-dbc8-485e-adba-a79d5ebee3ad",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "conditionals",
-        "strings"
-      ]
-    },
-    {
-      "slug": "matching-brackets",
-      "name": "Matching Brackets",
-      "uuid": "a2070019-e56d-4d48-994b-300411598707",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "parsing",
-        "strings"
-      ]
-    },
-    {
-      "slug": "spiral-matrix",
-      "name": "Spiral Matrix",
-      "uuid": "bae1f3a4-b63d-4efd-921a-133b3d5e379c",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "matrices"
-      ]
-    },
-    {
-      "slug": "tournament",
-      "name": "Tournament",
-      "uuid": "d9359f25-dc94-496c-adc3-57fe541857fe",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "parsing",
-        "strings"
-      ]
-    },
-    {
-      "slug": "variable-length-quantity",
-      "name": "Variable Length Quantity",
-      "uuid": "4c49ea84-8765-42b0-b4ab-5dead802eeee",
-      "prerequisites": [],
-      "difficulty": 7,
-      "topics": [
-        "algorithms",
-        "bitwise_operations"
-      ]
-    },
-    {
-      "slug": "dominoes",
-      "name": "Dominoes",
-      "uuid": "0409f45f-b65e-4404-a9e7-2ef432d834b2",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "arrays",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "forth",
-      "name": "Forth",
-      "uuid": "a2ba6202-f6e0-46f4-95e4-5921656f2e1a",
-      "prerequisites": [],
-      "difficulty": 10,
-      "topics": [
-        "parsing",
-        "stacks"
-      ]
-    },
-    {
-      "slug": "pangram",
-      "name": "Pangram",
-      "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "strings"
-      ]
-    },
-    {
-      "slug": "isogram",
-      "name": "Isogram",
-      "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "filtering",
-        "strings"
-      ]
-    },
-    {
-      "slug": "acronym",
-      "name": "Acronym",
-      "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "grains",
-      "name": "Grains",
-      "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "integers"
-      ]
-    },
-    {
-      "slug": "perfect-numbers",
-      "name": "Perfect Numbers",
-      "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "integers",
-        "math"
-      ]
-    },
-    {
-      "slug": "collatz-conjecture",
-      "name": "Collatz Conjecture",
-      "uuid": "c4efbf8a-8e76-4700-807d-830a4938f4d0",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "algorithms",
-        "conditionals",
-        "integers",
-        "loops",
-        "math"
-      ]
-    },
-    {
-      "slug": "phone-number",
-      "name": "Phone Number",
-      "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "scrabble-score",
-      "name": "Scrabble Score",
-      "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "transforming"
-      ]
-    },
-    {
-      "slug": "meetup",
-      "name": "Meetup",
-      "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "dates"
-      ]
-    },
-    {
-      "slug": "difference-of-squares",
-      "name": "Difference Of Squares",
-      "uuid": "5554c048-0de3-4a85-b043-7577f429cba4",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "integers",
-        "loops",
-        "math"
-      ]
-    },
-    {
-      "slug": "resistor-color-duo",
-      "name": "Resistor Color Duo",
-      "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "arrays"
-      ]
-    },
-    {
-      "slug": "resistor-color-trio",
-      "name": "Resistor Color Trio",
-      "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "arrays",
-        "conditionals"
-      ]
-    },
-    {
-      "slug": "series",
-      "name": "Series",
-      "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "arrays",
-        "strings"
-      ]
-    },
-    {
-      "slug": "sum-of-multiples",
-      "name": "Sum Of Multiples",
-      "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "arrays",
-        "math",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "accumulate",
-      "name": "Accumulate",
-      "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "extension_methods",
-        "sequences",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "all-your-base",
-      "name": "All Your Base",
-      "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "integers",
-        "math",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "largest-series-product",
-      "name": "Largest Series Product",
-      "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "integers",
-        "math",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "pascals-triangle",
-      "name": "Pascals Triangle",
-      "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "arrays",
-        "loops",
-        "math"
-      ]
-    },
-    {
-      "slug": "prime-factors",
-      "name": "Prime Factors",
-      "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "integers",
-        "math"
-      ]
-    },
-    {
-      "slug": "pythagorean-triplet",
-      "name": "Pythagorean Triplet",
-      "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "integers",
-        "math",
-        "overloading"
-      ]
-    },
-    {
-      "slug": "armstrong-numbers",
-      "name": "Armstrong Numbers",
-      "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "math"
-      ]
-    },
-    {
-      "slug": "darts",
-      "name": "Darts",
-      "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "floating_point_numbers",
-        "math"
-      ]
-    },
-    {
-      "slug": "triangle",
-      "name": "Triangle",
-      "uuid": "5b1713c7-1597-4e67-ac97-f305b207bc38",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "enumerations",
-        "integers"
-      ]
-    },
-    {
-      "slug": "rational-numbers",
-      "name": "Rational Numbers",
-      "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "math"
-      ]
-    },
-    {
-      "slug": "complex-numbers",
-      "name": "Complex Numbers",
-      "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "math",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "raindrops",
-      "name": "Raindrops",
-      "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "filtering",
-        "strings"
-      ]
-    },
-    {
-      "slug": "beer-song",
-      "name": "Beer Song",
-      "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "proverb",
-      "name": "Proverb",
-      "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "strain",
-      "name": "Strain",
-      "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "filtering",
-        "sequences"
-      ]
-    },
-    {
-      "slug": "house",
-      "name": "House",
-      "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "protein-translation",
-      "name": "Protein Translation",
-      "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "lists",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "roman-numerals",
-      "name": "Roman Numerals",
-      "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "loops",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "simple-cipher",
-      "name": "Simple Cipher",
-      "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "etl",
-      "name": "Etl",
-      "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
-      "prerequisites": [],
-      "difficulty": 2,
-      "topics": [
-        "dictionaries",
-        "lists",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "parallel-letter-frequency",
-      "name": "Parallel Letter Frequency",
-      "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "dictionaries",
-        "parallelism",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "alphametics",
-      "name": "Alphametics",
-      "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
-      "prerequisites": [],
-      "difficulty": 10,
-      "topics": [
-        "dictionaries",
-        "parsing"
-      ]
-    },
-    {
-      "slug": "sieve",
-      "name": "Sieve",
-      "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "filtering",
-        "math"
-      ]
-    },
-    {
-      "slug": "anagram",
-      "name": "Anagram",
-      "uuid": "790216d1-4fd9-4a9b-94f8-e1e07a18c2b7",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "filtering",
-        "strings"
-      ]
-    },
-    {
-      "slug": "binary-search",
-      "name": "Binary Search",
-      "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "arrays",
-        "searching"
-      ]
-    },
-    {
-      "slug": "kindergarten-garden",
-      "name": "Kindergarten Garden",
-      "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "enumerations",
-        "parsing"
-      ]
-    },
-    {
-      "slug": "secret-handshake",
-      "name": "Secret Handshake",
-      "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "arrays",
-        "bitwise_operations"
-      ]
-    },
-    {
-      "slug": "matrix",
-      "name": "Matrix",
-      "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "matrices",
-        "parsing"
-      ]
-    },
-    {
-      "slug": "crypto-square",
-      "name": "Crypto Square",
-      "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "food-chain",
-      "name": "Food Chain",
-      "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "minesweeper",
-      "name": "Minesweeper",
-      "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "scale-generator",
-      "name": "Scale Generator",
-      "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "parsing"
-      ]
-    },
-    {
-      "slug": "tree-building",
-      "name": "Tree Building",
-      "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "refactoring",
-        "trees"
-      ]
-    },
-    {
-      "slug": "change",
-      "name": "Change",
-      "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "arrays",
-        "integers"
-      ]
-    },
-    {
-      "slug": "rectangles",
-      "name": "Rectangles",
-      "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
-      "prerequisites": [],
-      "difficulty": 7,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "wordy",
-      "name": "Wordy",
-      "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
-      "prerequisites": [],
-      "difficulty": 7,
-      "topics": [
-        "parsing",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "connect",
-      "name": "Connect",
-      "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "sgf-parsing",
-      "name": "Sgf Parsing",
-      "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
-      "prerequisites": [],
-      "difficulty": 9,
-      "topics": [
-        "parsing",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "atbash-cipher",
-      "name": "Atbash Cipher",
-      "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "binary-search-tree",
-      "name": "Binary Search Tree",
-      "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "searching",
-        "trees"
-      ]
-    },
-    {
-      "slug": "flatten-array",
-      "name": "Flatten Array",
-      "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "lists",
-        "recursion"
-      ]
-    },
-    {
-      "slug": "list-ops",
-      "name": "List Ops",
-      "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "lists",
-        "recursion"
-      ]
-    },
-    {
-      "slug": "sublist",
-      "name": "Sublist",
-      "uuid": "89d3b074-190f-4520-8f87-cde6368fc58e",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "lists"
-      ]
-    },
-    {
-      "slug": "ledger",
-      "name": "Ledger",
-      "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "globalization",
-        "refactoring",
-        "strings"
-      ]
-    },
-    {
-      "slug": "ocr-numbers",
-      "name": "Ocr Numbers",
-      "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "parsing",
-        "pattern_recognition"
-      ]
-    },
-    {
-      "slug": "saddle-points",
-      "name": "Saddle Points",
-      "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "arrays",
-        "matrices",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "palindrome-products",
-      "name": "Palindrome Products",
-      "uuid": "165b8599-726d-43dd-8511-1401525810de",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "algorithms",
-        "math",
-        "strings",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "hangman",
-      "name": "Hangman",
-      "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "events",
-        "reactive_programming"
-      ]
-    },
-    {
-      "slug": "two-bucket",
-      "name": "Two Bucket",
-      "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "logic"
-      ]
-    },
-    {
-      "slug": "go-counting",
-      "name": "Go Counting",
-      "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
-      "prerequisites": [],
-      "difficulty": 9,
-      "topics": [
-        "optional_values",
-        "parsing",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "dnd-character",
-      "name": "Dnd Character",
-      "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "randomness"
-      ]
-    },
-    {
-      "slug": "queen-attack",
-      "name": "Queen Attack",
-      "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "classes"
-      ]
-    },
-    {
-      "slug": "robot-simulator",
-      "name": "Robot Simulator",
-      "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "classes",
-        "enumerations"
-      ]
-    },
-    {
-      "slug": "bank-account",
-      "name": "Bank Account",
-      "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "classes",
-        "concurrency"
-      ]
-    },
-    {
-      "slug": "simple-linked-list",
-      "name": "Simple Linked List",
-      "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "classes",
-        "lists"
-      ]
-    },
-    {
-      "slug": "error-handling",
-      "name": "Error Handling",
-      "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
-      "prerequisites": [],
-      "difficulty": 3,
-      "topics": [
-        "exception_handling"
-      ]
-    },
-    {
-      "slug": "affine-cipher",
-      "name": "Affine Cipher",
-      "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "cryptography",
-        "math",
-        "strings"
-      ]
-    },
-    {
-      "slug": "isbn-verifier",
-      "name": "Isbn Verifier",
-      "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "conditionals",
-        "loops",
-        "pattern_matching",
-        "strings"
-      ]
-    },
-    {
-      "slug": "twelve-days",
-      "name": "Twelve Days",
-      "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "word-count",
-      "name": "Word Count",
-      "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
-      "prerequisites": [],
-      "difficulty": 4,
-      "topics": [
-        "dictionaries",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "yacht",
-      "name": "Yacht",
-      "uuid": "f808e80a-8e76-4f3d-840e-31a840c560f2",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "games",
-        "parsing",
-        "sorting"
-      ]
-    },
-    {
-      "slug": "dot-dsl",
-      "name": "Dot Dsl",
-      "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "classes",
-        "domain_specific_languages",
-        "equality"
-      ]
-    },
-    {
-      "slug": "linked-list",
-      "name": "Linked List",
-      "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "classes",
-        "lists"
-      ]
-    },
-    {
-      "slug": "diamond",
-      "name": "Diamond",
-      "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "algorithms",
-        "strings"
-      ]
-    },
-    {
-      "slug": "grep",
-      "name": "Grep",
-      "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "files",
-        "searching",
-        "strings"
-      ]
-    },
-    {
-      "slug": "luhn",
-      "name": "Luhn",
-      "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "markdown",
-      "name": "Markdown",
-      "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "parsing",
-        "refactoring",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "word-search",
-      "name": "Word Search",
-      "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "searching",
-        "tuples"
-      ]
-    },
-    {
-      "slug": "bowling",
-      "name": "Bowling",
-      "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "algorithms",
-        "loops"
-      ]
-    },
-    {
-      "slug": "rest-api",
-      "name": "Rest Api",
-      "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "json",
-        "parsing"
-      ]
-    },
-    {
-      "slug": "poker",
-      "name": "Poker",
-      "uuid": "d03a9508-336a-4425-8f47-f04317d1ba15",
-      "prerequisites": [],
-      "difficulty": 7,
-      "topics": [
-        "games",
-        "parsing",
-        "sorting"
-      ]
-    },
-    {
-      "slug": "run-length-encoding",
-      "name": "Run Length Encoding",
-      "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "algorithms",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "pig-latin",
-      "name": "Pig Latin",
-      "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "transpose",
-      "name": "Transpose",
-      "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "say",
-      "name": "Say",
-      "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "book-store",
-      "name": "Book Store",
-      "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "recursion"
-      ]
-    },
-    {
-      "slug": "custom-set",
-      "name": "Custom Set",
-      "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
-      "prerequisites": [],
-      "difficulty": 5,
-      "topics": [
-        "sets"
-      ]
-    },
-    {
-      "slug": "nth-prime",
-      "name": "Nth Prime",
-      "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "math"
-      ]
-    },
-    {
-      "slug": "rail-fence-cipher",
-      "name": "Rail Fence Cipher",
-      "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
-      "prerequisites": [],
-      "difficulty": 6,
-      "topics": [
-        "algorithms",
-        "strings",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "diffie-hellman",
-      "name": "Diffie Hellman",
-      "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
-      "prerequisites": [],
-      "difficulty": 7,
-      "topics": [
-        "algorithms",
-        "integers",
-        "math",
-        "transforming"
-      ]
-    },
-    {
-      "slug": "zebra-puzzle",
-      "name": "Zebra Puzzle",
-      "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
-      "prerequisites": [],
-      "difficulty": 8,
-      "topics": [
-        "logic"
-      ]
-    },
-    {
-      "slug": "react",
-      "name": "React",
-      "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
-      "prerequisites": [],
-      "difficulty": 9,
-      "topics": [
-        "classes",
-        "events",
-        "reactive_programming"
-      ]
-    },
-    {
-      "slug": "pov",
-      "name": "Pov",
-      "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
-      "prerequisites": [],
-      "difficulty": 10,
-      "topics": [
-        "graphs",
-        "recursion",
-        "searching"
-      ]
-    },
-    {
-      "slug": "zipper",
-      "name": "Zipper",
-      "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
-      "prerequisites": [],
-      "difficulty": 10,
-      "topics": [
-        "recursion",
-        "searching",
-        "trees"
-      ]
-    },
-    {
-      "slug": "binary",
-      "name": "Binary",
-      "uuid": "cef7deef-54ce-4201-b263-7cd2098533f8",
-      "prerequisites": [],
-      "difficulty": 0,
-      "topics": null,
-      "status": "deprecated"
-    },
-    {
-      "slug": "hexadecimal",
-      "name": "Hexadecimal",
-      "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
-      "prerequisites": [],
-      "difficulty": 0,
-      "topics": null,
-      "status": "deprecated"
-    },
-    {
-      "slug": "octal",
-      "name": "Octal",
-      "uuid": "c8555f37-9976-4f52-a5db-6a680ec8d53b",
-      "prerequisites": [],
-      "difficulty": 0,
-      "topics": null,
-      "status": "deprecated"
-    },
-    {
-      "slug": "trinary",
-      "name": "Trinary",
-      "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
-      "prerequisites": [],
-      "difficulty": 0,
-      "topics": null,
-      "status": "deprecated"
-    },
-    {
-      "slug": "reverse-string",
-      "name": "Reverse String",
-      "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "strings"
-      ]
-    },
-    {
-      "slug": "rna-transcription",
-      "name": "Rna Transcription",
-      "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
-      "prerequisites": [],
-      "difficulty": 1,
-      "topics": [
-        "strings",
-        "transforming"
-      ]
-    }
-  ]
+  "exercises": {
+    "practice": [
+      {
+        "slug": "hello-world",
+        "name": "Hello World",
+        "uuid": "6c88f46b-5acb-4fae-a6ec-b48ae3f8168f",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "strings"
+        ]
+      },
+      {
+        "slug": "two-fer",
+        "name": "Two Fer",
+        "uuid": "57f02d0e-7b75-473b-892d-26a7d980c4ce",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "optional_values",
+          "strings"
+        ]
+      },
+      {
+        "slug": "leap",
+        "name": "Leap",
+        "uuid": "8ba15933-29a2-49b1-a9ce-70474bad3007",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "conditionals",
+          "integers"
+        ]
+      },
+      {
+        "slug": "gigasecond",
+        "name": "Gigasecond",
+        "uuid": "b7116dfb-1107-4546-9f95-f15acdb6f6a4",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "dates"
+        ]
+      },
+      {
+        "slug": "resistor-color",
+        "name": "Resistor Color",
+        "uuid": "5314dbee-4a0d-4fd6-a98a-36a746ee0d5c",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "arrays"
+        ]
+      },
+      {
+        "slug": "space-age",
+        "name": "Space Age",
+        "uuid": "612f058b-c6d9-4c97-913a-eeeb59ef61e1",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "floating_point_numbers"
+        ]
+      },
+      {
+        "slug": "high-scores",
+        "name": "High Scores",
+        "uuid": "f52d9be9-7044-4001-8678-dcae91a8d7f3",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "lists"
+        ]
+      },
+      {
+        "slug": "hamming",
+        "name": "Hamming",
+        "uuid": "05162ee0-38ac-40ad-a591-d70a74b6963a",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "filtering",
+          "strings"
+        ]
+      },
+      {
+        "slug": "nucleotide-count",
+        "name": "Nucleotide Count",
+        "uuid": "caca1c6a-b998-431e-b6af-ca2d47b7708f",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "dictionaries",
+          "strings"
+        ]
+      },
+      {
+        "slug": "robot-name",
+        "name": "Robot Name",
+        "uuid": "46b8aea8-1528-43cb-a754-495ec2790ce2",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "classes",
+          "randomness",
+          "strings"
+        ]
+      },
+      {
+        "slug": "allergies",
+        "name": "Allergies",
+        "uuid": "2ac228d8-7bf0-4946-8352-6541df02c0a2",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "bitwise_operations",
+          "filtering"
+        ]
+      },
+      {
+        "slug": "grade-school",
+        "name": "Grade School",
+        "uuid": "ec1cc254-8e66-40d0-87bf-971d54c541c4",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "lists",
+          "sorting"
+        ]
+      },
+      {
+        "slug": "rotational-cipher",
+        "name": "Rotational Cipher",
+        "uuid": "8a0a291d-8330-4901-bdbe-f974e163158e",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "circular-buffer",
+        "name": "Circular Buffer",
+        "uuid": "657ac368-9b17-4f87-b815-decfe2bc0b5d",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "classes",
+          "queues"
+        ]
+      },
+      {
+        "slug": "clock",
+        "name": "Clock",
+        "uuid": "83e4cb1e-456f-4c74-ae82-6895f0bd73ae",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "classes",
+          "equality"
+        ]
+      },
+      {
+        "slug": "bob",
+        "name": "Bob",
+        "uuid": "da00f894-dbc8-485e-adba-a79d5ebee3ad",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "conditionals",
+          "strings"
+        ]
+      },
+      {
+        "slug": "matching-brackets",
+        "name": "Matching Brackets",
+        "uuid": "a2070019-e56d-4d48-994b-300411598707",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "parsing",
+          "strings"
+        ]
+      },
+      {
+        "slug": "spiral-matrix",
+        "name": "Spiral Matrix",
+        "uuid": "bae1f3a4-b63d-4efd-921a-133b3d5e379c",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "matrices"
+        ]
+      },
+      {
+        "slug": "tournament",
+        "name": "Tournament",
+        "uuid": "d9359f25-dc94-496c-adc3-57fe541857fe",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "parsing",
+          "strings"
+        ]
+      },
+      {
+        "slug": "variable-length-quantity",
+        "name": "Variable Length Quantity",
+        "uuid": "4c49ea84-8765-42b0-b4ab-5dead802eeee",
+        "prerequisites": [],
+        "difficulty": 7,
+        "topics": [
+          "algorithms",
+          "bitwise_operations"
+        ]
+      },
+      {
+        "slug": "dominoes",
+        "name": "Dominoes",
+        "uuid": "0409f45f-b65e-4404-a9e7-2ef432d834b2",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "arrays",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "forth",
+        "name": "Forth",
+        "uuid": "a2ba6202-f6e0-46f4-95e4-5921656f2e1a",
+        "prerequisites": [],
+        "difficulty": 10,
+        "topics": [
+          "parsing",
+          "stacks"
+        ]
+      },
+      {
+        "slug": "pangram",
+        "name": "Pangram",
+        "uuid": "a595d7a1-81d3-48f2-9921-e53b9b22e072",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "strings"
+        ]
+      },
+      {
+        "slug": "isogram",
+        "name": "Isogram",
+        "uuid": "4b7b65be-f777-4f64-94a0-4f9832f17a52",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "filtering",
+          "strings"
+        ]
+      },
+      {
+        "slug": "acronym",
+        "name": "Acronym",
+        "uuid": "ddfb0a0e-8c58-4b9e-ad62-57d06ef10f5f",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "grains",
+        "name": "Grains",
+        "uuid": "372c71b6-6256-4fe2-bddc-55667e3861af",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "integers"
+        ]
+      },
+      {
+        "slug": "perfect-numbers",
+        "name": "Perfect Numbers",
+        "uuid": "142c97b6-ae31-4b5f-944c-3eb789d9e051",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "integers",
+          "math"
+        ]
+      },
+      {
+        "slug": "collatz-conjecture",
+        "name": "Collatz Conjecture",
+        "uuid": "c4efbf8a-8e76-4700-807d-830a4938f4d0",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "algorithms",
+          "conditionals",
+          "integers",
+          "loops",
+          "math"
+        ]
+      },
+      {
+        "slug": "phone-number",
+        "name": "Phone Number",
+        "uuid": "5675771e-1a46-40bd-8923-f6e09642cc0c",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "parsing",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "scrabble-score",
+        "name": "Scrabble Score",
+        "uuid": "89c42da3-72a6-423d-a9c7-7caccbd9b1e6",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "transforming"
+        ]
+      },
+      {
+        "slug": "meetup",
+        "name": "Meetup",
+        "uuid": "064096c1-89b0-4656-bd3e-08ca833aa0b1",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "dates"
+        ]
+      },
+      {
+        "slug": "difference-of-squares",
+        "name": "Difference Of Squares",
+        "uuid": "5554c048-0de3-4a85-b043-7577f429cba4",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "integers",
+          "loops",
+          "math"
+        ]
+      },
+      {
+        "slug": "resistor-color-duo",
+        "name": "Resistor Color Duo",
+        "uuid": "415b9893-c366-4ac1-a904-e0fccfcf18c7",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "arrays"
+        ]
+      },
+      {
+        "slug": "resistor-color-trio",
+        "name": "Resistor Color Trio",
+        "uuid": "328e6978-0384-445b-b07a-adfd017a9eff",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "arrays",
+          "conditionals"
+        ]
+      },
+      {
+        "slug": "series",
+        "name": "Series",
+        "uuid": "9ca46617-4995-45cc-a2dd-b8630eaa288b",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "arrays",
+          "strings"
+        ]
+      },
+      {
+        "slug": "sum-of-multiples",
+        "name": "Sum Of Multiples",
+        "uuid": "d985d4a9-1a2b-4bb1-ad08-961b8d36ee2e",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "arrays",
+          "math",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "accumulate",
+        "name": "Accumulate",
+        "uuid": "3c0563dc-665a-45b4-9b29-f133e235efd0",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "extension_methods",
+          "sequences",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "all-your-base",
+        "name": "All Your Base",
+        "uuid": "de5e2eff-2b80-4996-a322-dc59ebe25edd",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "integers",
+          "math",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "largest-series-product",
+        "name": "Largest Series Product",
+        "uuid": "4a6621bb-e55a-4ae2-89e3-3aa7e37a8656",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "integers",
+          "math",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "pascals-triangle",
+        "name": "Pascals Triangle",
+        "uuid": "d5d48857-5325-45d2-9969-95a0d7bba370",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "arrays",
+          "loops",
+          "math"
+        ]
+      },
+      {
+        "slug": "prime-factors",
+        "name": "Prime Factors",
+        "uuid": "456ffe2c-e241-4373-8bea-d4d328f815e9",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "integers",
+          "math"
+        ]
+      },
+      {
+        "slug": "pythagorean-triplet",
+        "name": "Pythagorean Triplet",
+        "uuid": "4d5a53df-3d6b-46cb-a964-71c676f3cd93",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "integers",
+          "math",
+          "overloading"
+        ]
+      },
+      {
+        "slug": "armstrong-numbers",
+        "name": "Armstrong Numbers",
+        "uuid": "8150604d-4cdc-414a-a523-dd65ac536f0e",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "math"
+        ]
+      },
+      {
+        "slug": "darts",
+        "name": "Darts",
+        "uuid": "cdde6c8c-0608-467d-a749-b53ec6168ecc",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "floating_point_numbers",
+          "math"
+        ]
+      },
+      {
+        "slug": "triangle",
+        "name": "Triangle",
+        "uuid": "5b1713c7-1597-4e67-ac97-f305b207bc38",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "enumerations",
+          "integers"
+        ]
+      },
+      {
+        "slug": "rational-numbers",
+        "name": "Rational Numbers",
+        "uuid": "9ae7f7ed-75d8-4d03-967c-53846634ae07",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "math"
+        ]
+      },
+      {
+        "slug": "complex-numbers",
+        "name": "Complex Numbers",
+        "uuid": "0ed2de0f-70da-4f04-834e-01bfb0aa48d3",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "math",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "raindrops",
+        "name": "Raindrops",
+        "uuid": "29ae7f8e-a009-4175-9350-a8c684c89730",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "filtering",
+          "strings"
+        ]
+      },
+      {
+        "slug": "beer-song",
+        "name": "Beer Song",
+        "uuid": "4ae402a7-5345-429a-a6af-e95ec5b95e13",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "proverb",
+        "name": "Proverb",
+        "uuid": "b0a978a6-9c3f-427e-8ada-0a3951ca14fd",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "strain",
+        "name": "Strain",
+        "uuid": "fdb19da7-28df-429b-83e5-d024abe97870",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "filtering",
+          "sequences"
+        ]
+      },
+      {
+        "slug": "house",
+        "name": "House",
+        "uuid": "97aa0e82-2fc3-49e2-ad27-faef2873b328",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "protein-translation",
+        "name": "Protein Translation",
+        "uuid": "75a2d5f0-5f5e-46a3-9dd2-3da415690e18",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "lists",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "roman-numerals",
+        "name": "Roman Numerals",
+        "uuid": "d3702b93-7bb3-4e0a-8cd7-974ad93b0d3d",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "loops",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "simple-cipher",
+        "name": "Simple Cipher",
+        "uuid": "54649fb0-6b14-44df-85af-ae1f7a62449d",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "etl",
+        "name": "Etl",
+        "uuid": "36b7602c-44e2-4589-a97d-127a0277b2a2",
+        "prerequisites": [],
+        "difficulty": 2,
+        "topics": [
+          "dictionaries",
+          "lists",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "parallel-letter-frequency",
+        "name": "Parallel Letter Frequency",
+        "uuid": "5863c898-2072-4543-9ab5-045fd6691de4",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "dictionaries",
+          "parallelism",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "alphametics",
+        "name": "Alphametics",
+        "uuid": "c6961cae-5e93-470a-98ce-e7cd6b9cfcbf",
+        "prerequisites": [],
+        "difficulty": 10,
+        "topics": [
+          "dictionaries",
+          "parsing"
+        ]
+      },
+      {
+        "slug": "sieve",
+        "name": "Sieve",
+        "uuid": "1897605a-afd4-49fe-b6ee-cd822f0d8acc",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "filtering",
+          "math"
+        ]
+      },
+      {
+        "slug": "anagram",
+        "name": "Anagram",
+        "uuid": "790216d1-4fd9-4a9b-94f8-e1e07a18c2b7",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "filtering",
+          "strings"
+        ]
+      },
+      {
+        "slug": "binary-search",
+        "name": "Binary Search",
+        "uuid": "f92ff94a-73e6-41cb-a376-835c2368b358",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "arrays",
+          "searching"
+        ]
+      },
+      {
+        "slug": "kindergarten-garden",
+        "name": "Kindergarten Garden",
+        "uuid": "b7458404-2534-4ed8-8350-7060fa4b5786",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "enumerations",
+          "parsing"
+        ]
+      },
+      {
+        "slug": "secret-handshake",
+        "name": "Secret Handshake",
+        "uuid": "1ad236a9-7035-42e6-90ec-f6a4b94ad495",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "arrays",
+          "bitwise_operations"
+        ]
+      },
+      {
+        "slug": "matrix",
+        "name": "Matrix",
+        "uuid": "73509caa-9b3e-4d09-933f-364c1a7e5519",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "matrices",
+          "parsing"
+        ]
+      },
+      {
+        "slug": "crypto-square",
+        "name": "Crypto Square",
+        "uuid": "dd95f3d8-6da4-4bb4-b5c1-bf00c818d586",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "food-chain",
+        "name": "Food Chain",
+        "uuid": "3a09736e-4002-41aa-acf9-ff10a9392b24",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "minesweeper",
+        "name": "Minesweeper",
+        "uuid": "466f17d4-13d0-4d6e-8564-c8bdfede35d1",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "parsing",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "scale-generator",
+        "name": "Scale Generator",
+        "uuid": "c7d5acc6-68a6-4cd8-a28b-359dceb1e56f",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "parsing"
+        ]
+      },
+      {
+        "slug": "tree-building",
+        "name": "Tree Building",
+        "uuid": "b31bff08-a609-40ec-a1ee-46ba24e671f2",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "refactoring",
+          "trees"
+        ]
+      },
+      {
+        "slug": "change",
+        "name": "Change",
+        "uuid": "44796c6c-39b3-41c7-8ea5-ffb9738423b8",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "arrays",
+          "integers"
+        ]
+      },
+      {
+        "slug": "rectangles",
+        "name": "Rectangles",
+        "uuid": "817ccde1-0593-4091-85a5-616f4f8823f0",
+        "prerequisites": [],
+        "difficulty": 7,
+        "topics": [
+          "parsing",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "wordy",
+        "name": "Wordy",
+        "uuid": "57ef1936-d187-4915-888b-374f09c794c7",
+        "prerequisites": [],
+        "difficulty": 7,
+        "topics": [
+          "parsing",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "connect",
+        "name": "Connect",
+        "uuid": "ca56c362-c9f5-4403-9a2d-2e31e54b35e3",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "parsing",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "sgf-parsing",
+        "name": "Sgf Parsing",
+        "uuid": "da255a02-8007-41e4-8a9e-7e2cfbe81be5",
+        "prerequisites": [],
+        "difficulty": 9,
+        "topics": [
+          "parsing",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "atbash-cipher",
+        "name": "Atbash Cipher",
+        "uuid": "0c5918d5-15cc-401f-b038-5fb2cd515ec7",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "binary-search-tree",
+        "name": "Binary Search Tree",
+        "uuid": "d40541a8-d7d6-4dab-8560-27c5055adbd0",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "searching",
+          "trees"
+        ]
+      },
+      {
+        "slug": "flatten-array",
+        "name": "Flatten Array",
+        "uuid": "9ad05373-a049-47f9-a06a-80ad0a7b38fd",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "lists",
+          "recursion"
+        ]
+      },
+      {
+        "slug": "list-ops",
+        "name": "List Ops",
+        "uuid": "3b5b11b0-9476-4d9b-a4c5-c5c48d3d32a8",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "lists",
+          "recursion"
+        ]
+      },
+      {
+        "slug": "sublist",
+        "name": "Sublist",
+        "uuid": "89d3b074-190f-4520-8f87-cde6368fc58e",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "lists"
+        ]
+      },
+      {
+        "slug": "ledger",
+        "name": "Ledger",
+        "uuid": "c1cc752e-99a2-4da3-8d0c-82e08f1c6110",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "globalization",
+          "refactoring",
+          "strings"
+        ]
+      },
+      {
+        "slug": "ocr-numbers",
+        "name": "Ocr Numbers",
+        "uuid": "2a5ddf5e-e677-4eef-b759-087d71e15986",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "parsing",
+          "pattern_recognition"
+        ]
+      },
+      {
+        "slug": "saddle-points",
+        "name": "Saddle Points",
+        "uuid": "cb755a7d-e01d-4758-92ab-9d2e6518a3eb",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "arrays",
+          "matrices",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "palindrome-products",
+        "name": "Palindrome Products",
+        "uuid": "165b8599-726d-43dd-8511-1401525810de",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "algorithms",
+          "math",
+          "strings",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "hangman",
+        "name": "Hangman",
+        "uuid": "c9b12d50-09dc-4f43-9e7e-66b277432347",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "events",
+          "reactive_programming"
+        ]
+      },
+      {
+        "slug": "two-bucket",
+        "name": "Two Bucket",
+        "uuid": "b33c3b86-e04b-4529-bdf5-9d553ad59f87",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "logic"
+        ]
+      },
+      {
+        "slug": "go-counting",
+        "name": "Go Counting",
+        "uuid": "1abbc58c-9a04-4b6f-afe1-85d3e4d202e1",
+        "prerequisites": [],
+        "difficulty": 9,
+        "topics": [
+          "optional_values",
+          "parsing",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "dnd-character",
+        "name": "Dnd Character",
+        "uuid": "eb93b46e-203b-43f0-ad5c-de8d5ccf2061",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "randomness"
+        ]
+      },
+      {
+        "slug": "queen-attack",
+        "name": "Queen Attack",
+        "uuid": "5c56211a-ae1e-4836-80b5-f22f5801b7a2",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "classes"
+        ]
+      },
+      {
+        "slug": "robot-simulator",
+        "name": "Robot Simulator",
+        "uuid": "babd38cc-cf21-42ca-9d33-f2ad75c82871",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "classes",
+          "enumerations"
+        ]
+      },
+      {
+        "slug": "bank-account",
+        "name": "Bank Account",
+        "uuid": "96c641c8-4c3c-47ff-9e32-9722b5ca2c37",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "classes",
+          "concurrency"
+        ]
+      },
+      {
+        "slug": "simple-linked-list",
+        "name": "Simple Linked List",
+        "uuid": "2d68e971-d717-4196-a348-d4675a47283a",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "classes",
+          "lists"
+        ]
+      },
+      {
+        "slug": "error-handling",
+        "name": "Error Handling",
+        "uuid": "77e46f6b-1070-4267-a1b5-a2aac931975a",
+        "prerequisites": [],
+        "difficulty": 3,
+        "topics": [
+          "exception_handling"
+        ]
+      },
+      {
+        "slug": "affine-cipher",
+        "name": "Affine Cipher",
+        "uuid": "2462D9AE-6483-40C6-955A-79CB2AC25B34",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "cryptography",
+          "math",
+          "strings"
+        ]
+      },
+      {
+        "slug": "isbn-verifier",
+        "name": "Isbn Verifier",
+        "uuid": "d714b1e6-48b5-44d6-9661-d0acd3dd657b",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "conditionals",
+          "loops",
+          "pattern_matching",
+          "strings"
+        ]
+      },
+      {
+        "slug": "twelve-days",
+        "name": "Twelve Days",
+        "uuid": "2627fb4f-7884-4494-8f49-5888107643f1",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "word-count",
+        "name": "Word Count",
+        "uuid": "6e8717a7-6888-474a-96ad-0760c6d3ff92",
+        "prerequisites": [],
+        "difficulty": 4,
+        "topics": [
+          "dictionaries",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "yacht",
+        "name": "Yacht",
+        "uuid": "f808e80a-8e76-4f3d-840e-31a840c560f2",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "games",
+          "parsing",
+          "sorting"
+        ]
+      },
+      {
+        "slug": "dot-dsl",
+        "name": "Dot Dsl",
+        "uuid": "d128ec4b-190f-4726-b3e7-870be09531aa",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "classes",
+          "domain_specific_languages",
+          "equality"
+        ]
+      },
+      {
+        "slug": "linked-list",
+        "name": "Linked List",
+        "uuid": "49b557ad-0bf0-451b-9a12-6dd9eb0291a2",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "classes",
+          "lists"
+        ]
+      },
+      {
+        "slug": "diamond",
+        "name": "Diamond",
+        "uuid": "2f3faeb7-7cc3-42ed-9525-cd9c73922a8d",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "algorithms",
+          "strings"
+        ]
+      },
+      {
+        "slug": "grep",
+        "name": "Grep",
+        "uuid": "a9909a03-ce2e-45d9-85f8-a77f44fb2466",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "files",
+          "searching",
+          "strings"
+        ]
+      },
+      {
+        "slug": "luhn",
+        "name": "Luhn",
+        "uuid": "20fe4853-0eee-4171-b3c1-8ef871b99d13",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "markdown",
+        "name": "Markdown",
+        "uuid": "dee4abe1-c75f-4cb8-b5f3-5b5b77e1c7aa",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "parsing",
+          "refactoring",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "word-search",
+        "name": "Word Search",
+        "uuid": "2b05d7dd-0f0b-4fa4-a2bf-9d7fa28a7543",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "searching",
+          "tuples"
+        ]
+      },
+      {
+        "slug": "bowling",
+        "name": "Bowling",
+        "uuid": "64eff1cb-990d-45bc-a9e7-8f574e114ece",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "algorithms",
+          "loops"
+        ]
+      },
+      {
+        "slug": "rest-api",
+        "name": "Rest Api",
+        "uuid": "4c89b6a8-0e89-46c9-5a7e-31bfe6a57007",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "json",
+          "parsing"
+        ]
+      },
+      {
+        "slug": "poker",
+        "name": "Poker",
+        "uuid": "d03a9508-336a-4425-8f47-f04317d1ba15",
+        "prerequisites": [],
+        "difficulty": 7,
+        "topics": [
+          "games",
+          "parsing",
+          "sorting"
+        ]
+      },
+      {
+        "slug": "run-length-encoding",
+        "name": "Run Length Encoding",
+        "uuid": "4ad0d49a-e10b-4f8b-b454-623b9396d559",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "algorithms",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "pig-latin",
+        "name": "Pig Latin",
+        "uuid": "63bdd2d4-b395-41ca-8c58-b3d94bf1e696",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "transpose",
+        "name": "Transpose",
+        "uuid": "2634c53c-ba4d-4729-b936-a7ec387f4789",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "say",
+        "name": "Say",
+        "uuid": "34518ea7-c202-443a-b28f-e873f3207f89",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "book-store",
+        "name": "Book Store",
+        "uuid": "8288d3e0-75a4-4a18-94c7-2fab3228dc58",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "recursion"
+        ]
+      },
+      {
+        "slug": "custom-set",
+        "name": "Custom Set",
+        "uuid": "a6dff389-07ea-42cb-98ec-271ce7cfeda3",
+        "prerequisites": [],
+        "difficulty": 5,
+        "topics": [
+          "sets"
+        ]
+      },
+      {
+        "slug": "nth-prime",
+        "name": "Nth Prime",
+        "uuid": "60ef0713-70e2-4ee7-9207-86910e616ec1",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "math"
+        ]
+      },
+      {
+        "slug": "rail-fence-cipher",
+        "name": "Rail Fence Cipher",
+        "uuid": "e338fed5-f850-4922-88b2-7e9ec0eb7299",
+        "prerequisites": [],
+        "difficulty": 6,
+        "topics": [
+          "algorithms",
+          "strings",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "diffie-hellman",
+        "name": "Diffie Hellman",
+        "uuid": "3bea029d-ccc2-48be-90f3-84bf2d5b825b",
+        "prerequisites": [],
+        "difficulty": 7,
+        "topics": [
+          "algorithms",
+          "integers",
+          "math",
+          "transforming"
+        ]
+      },
+      {
+        "slug": "zebra-puzzle",
+        "name": "Zebra Puzzle",
+        "uuid": "e167479e-e77d-4734-b8c0-a7cd686c74a3",
+        "prerequisites": [],
+        "difficulty": 8,
+        "topics": [
+          "logic"
+        ]
+      },
+      {
+        "slug": "react",
+        "name": "React",
+        "uuid": "3e86c66d-c66e-4e28-834d-09b33b2ee2d2",
+        "prerequisites": [],
+        "difficulty": 9,
+        "topics": [
+          "classes",
+          "events",
+          "reactive_programming"
+        ]
+      },
+      {
+        "slug": "pov",
+        "name": "Pov",
+        "uuid": "a5794706-58d2-48f7-8aab-78639d7bce77",
+        "prerequisites": [],
+        "difficulty": 10,
+        "topics": [
+          "graphs",
+          "recursion",
+          "searching"
+        ]
+      },
+      {
+        "slug": "zipper",
+        "name": "Zipper",
+        "uuid": "db77fbd1-29d9-40e6-a32e-9fb89acdc9fc",
+        "prerequisites": [],
+        "difficulty": 10,
+        "topics": [
+          "recursion",
+          "searching",
+          "trees"
+        ]
+      },
+      {
+        "slug": "binary",
+        "name": "Binary",
+        "uuid": "cef7deef-54ce-4201-b263-7cd2098533f8",
+        "prerequisites": [],
+        "difficulty": 0,
+        "topics": null,
+        "status": "deprecated"
+      },
+      {
+        "slug": "hexadecimal",
+        "name": "Hexadecimal",
+        "uuid": "5d30c5a0-0f69-4b79-8c7e-3b1fe6a5707f",
+        "prerequisites": [],
+        "difficulty": 0,
+        "topics": null,
+        "status": "deprecated"
+      },
+      {
+        "slug": "octal",
+        "name": "Octal",
+        "uuid": "c8555f37-9976-4f52-a5db-6a680ec8d53b",
+        "prerequisites": [],
+        "difficulty": 0,
+        "topics": null,
+        "status": "deprecated"
+      },
+      {
+        "slug": "trinary",
+        "name": "Trinary",
+        "uuid": "c7dd8467-87e2-4997-a96e-a04cb8b891e8",
+        "prerequisites": [],
+        "difficulty": 0,
+        "topics": null,
+        "status": "deprecated"
+      },
+      {
+        "slug": "reverse-string",
+        "name": "Reverse String",
+        "uuid": "14395318-c7b9-11e7-abc4-cec278b6b50a",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "strings"
+        ]
+      },
+      {
+        "slug": "rna-transcription",
+        "name": "Rna Transcription",
+        "uuid": "440b0b23-220d-4706-98f0-9a89fce85acb",
+        "prerequisites": [],
+        "difficulty": 1,
+        "topics": [
+          "strings",
+          "transforming"
+        ]
+      }
+    ]
+  }
 }

From dbf1ce905b7ce8f07070fb4f294a9977c47eb023 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:50 +0100
Subject: [PATCH 308/327] [v3] Move foregone exercises to exercises property in
 config.json

---
 config.json | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/config.json b/config.json
index a8f93e3984..d3fa2faf47 100644
--- a/config.json
+++ b/config.json
@@ -14,13 +14,6 @@
     "indent_style": "space",
     "indent_size": 4
   },
-  "foregone": [
-    "lens-person",
-    "nucleotide-codons",
-    "paasio",
-    "point-mutations",
-    "counter"
-  ],
   "exercises": {
     "practice": [
       {
@@ -1420,6 +1413,13 @@
           "transforming"
         ]
       }
+    ],
+    "foregone": [
+      "lens-person",
+      "nucleotide-codons",
+      "paasio",
+      "point-mutations",
+      "counter"
     ]
   }
 }

From 88697958aed1572d148223257447b82f04d952fc Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:51 +0100
Subject: [PATCH 309/327] [v3] Add concept exercises to config.json

---
 config.json | 569 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 569 insertions(+)

diff --git a/config.json b/config.json
index d3fa2faf47..393af91a14 100644
--- a/config.json
+++ b/config.json
@@ -15,6 +15,575 @@
     "indent_size": 4
   },
   "exercises": {
+    "concept": [
+      {
+        "slug": "bird-watcher",
+        "name": "Bird Watcher",
+        "uuid": "b6c532c9-1e89-4fbf-8f08-27f5befb5bb8",
+        "concepts": [
+          "arrays",
+          "for-loops",
+          "foreach-loops"
+        ],
+        "prerequisites": [
+          "booleans",
+          "classes",
+          "if-statements"
+        ]
+      },
+      {
+        "slug": "lucians-luscious-lasagna",
+        "name": "Lucian's Luscious Lasagna",
+        "uuid": "7d358894-4fbd-4c91-b49f-d68f1c5aa6bc",
+        "concepts": [
+          "basics"
+        ],
+        "prerequisites": []
+      },
+      {
+        "slug": "annalyns-infiltration",
+        "name": "Annalyn's Infiltration",
+        "uuid": "401fe55e-407e-4408-88ca-0a4b342ab95b",
+        "concepts": [
+          "booleans"
+        ],
+        "prerequisites": [
+          "basics"
+        ]
+      },
+      {
+        "slug": "secure-munchester-united",
+        "name": "Secure Munchester United",
+        "uuid": "0d63645d-385a-43ea-b89e-448ed608f6ce",
+        "concepts": [
+          "casting"
+        ],
+        "prerequisites": [
+          "exceptions",
+          "inheritance",
+          "numbers"
+        ]
+      },
+      {
+        "slug": "squeaky-clean",
+        "name": "Squeaky Clean",
+        "uuid": "e74c6cd6-add7-45d1-abcb-513418e9d2d0",
+        "concepts": [
+          "chars",
+          "string-builder"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "for-loops",
+          "strings"
+        ]
+      },
+      {
+        "slug": "elons-toys",
+        "name": "Elon's Toys",
+        "uuid": "e01dc85b-0731-4701-9eea-c78fb69ce543",
+        "concepts": [
+          "classes"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "numbers",
+          "strings"
+        ]
+      },
+      {
+        "slug": "authentication-system",
+        "name": "Authentication System",
+        "uuid": "54126398-4339-4073-9f5d-cf71cabcb328",
+        "concepts": [
+          "constants",
+          "defensive-copying",
+          "readonly-collections"
+        ],
+        "prerequisites": [
+          "arrays",
+          "basics",
+          "classes",
+          "dictionaries",
+          "nested-types",
+          "object-initializers",
+          "properties"
+        ]
+      },
+      {
+        "slug": "need-for-speed",
+        "name": "Need for Speed",
+        "uuid": "655b5c37-c2eb-4da2-ab0a-3845de898835",
+        "concepts": [
+          "constructors"
+        ],
+        "prerequisites": [
+          "classes",
+          "if-statements",
+          "numbers",
+          "while-loops"
+        ]
+      },
+      {
+        "slug": "booking-up-for-beauty",
+        "name": "Booking up for Beauty",
+        "uuid": "7762d9ec-ca95-4e10-b93c-afd2521787a2",
+        "concepts": [
+          "datetimes"
+        ],
+        "prerequisites": [
+          "classes",
+          "numbers",
+          "strings"
+        ]
+      },
+      {
+        "slug": "international-calling-connoisseur",
+        "name": "International Calling Connoisseur",
+        "uuid": "ea01c7d9-a387-451b-9a69-f1b48f00d7a5",
+        "concepts": [
+          "dictionaries"
+        ],
+        "prerequisites": [
+          "foreach-loops",
+          "generic-types",
+          "strings",
+          "indexers"
+        ]
+      },
+      {
+        "slug": "logs-logs-logs",
+        "name": "Logs, Logs, Logs!",
+        "uuid": "047b895b-7039-4af6-ad3a-17fd818d0b88",
+        "concepts": [
+          "enums"
+        ],
+        "prerequisites": [
+          "strings",
+          "switch-statements"
+        ]
+      },
+      {
+        "slug": "faceid-2",
+        "name": "Face ID 2.0",
+        "uuid": "116e0b8d-21f2-409f-abec-676da014a800",
+        "concepts": [
+          "equality",
+          "sets"
+        ],
+        "prerequisites": [
+          "classes",
+          "explicit-casts",
+          "generic-types",
+          "inheritance",
+          "interfaces",
+          "lists"
+        ]
+      },
+      {
+        "slug": "calculator-conundrum",
+        "name": "Calculator Conundrum",
+        "uuid": "b140614f-36df-4ce9-a539-97a81304b941",
+        "concepts": [
+          "exceptions"
+        ],
+        "prerequisites": [
+          "inheritance",
+          "nullability",
+          "switch-statements"
+        ]
+      },
+      {
+        "slug": "the-weather-in-deather",
+        "name": "The Weather in Deather",
+        "uuid": "27221c37-177e-437b-b423-977e46695db9",
+        "concepts": [
+          "ternary-operators",
+          "expression-bodied-members",
+          "switch-expressions",
+          "throw-expressions"
+        ],
+        "prerequisites": [
+          "booleans",
+          "classes",
+          "if-statements",
+          "constructors",
+          "datetimes",
+          "exceptions",
+          "properties",
+          "switch-statements"
+        ]
+      },
+      {
+        "slug": "attack-of-the-trolls",
+        "name": "Attack of the Trolls",
+        "uuid": "ad240550-d732-4125-b00b-b852027a2db7",
+        "concepts": [
+          "attributes",
+          "flag-enums"
+        ],
+        "prerequisites": [
+          "bit-manipulation",
+          "enums",
+          "integral-numbers"
+        ]
+      },
+      {
+        "slug": "interest-is-interesting",
+        "name": "Interest is Interesting",
+        "uuid": "4eb8d86f-7123-473e-9d96-7939e9652608",
+        "concepts": [
+          "do-while-loops",
+          "floating-point-numbers",
+          "while-loops"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "numbers"
+        ]
+      },
+      {
+        "slug": "wizards-and-warriors",
+        "name": "Wizards and Warriors",
+        "uuid": "2eecc903-a3d9-47dd-ac62-1d88505f089c",
+        "concepts": [
+          "inheritance"
+        ],
+        "prerequisites": [
+          "booleans",
+          "classes",
+          "if-statements",
+          "constructors",
+          "strings"
+        ]
+      },
+      {
+        "slug": "hyper-optimized-telemetry",
+        "name": "Hyper-optimized Telemetry",
+        "uuid": "86bbc073-1726-423d-b156-c394554a4a8c",
+        "concepts": [
+          "integral-numbers"
+        ],
+        "prerequisites": [
+          "arrays",
+          "numbers"
+        ]
+      },
+      {
+        "slug": "remote-control-competition",
+        "name": "Remote Control Competition",
+        "uuid": "15ac87b1-2976-4a43-a41d-1b6f6628bd9a",
+        "concepts": [
+          "interfaces",
+          "ordering"
+        ],
+        "prerequisites": [
+          "classes",
+          "lists",
+          "properties"
+        ]
+      },
+      {
+        "slug": "tracks-on-tracks-on-tracks",
+        "name": "Tracks on Tracks on Tracks",
+        "uuid": "5c438d02-67a6-43b6-9e3c-8ba309c4ea32",
+        "concepts": [
+          "generic-types",
+          "lists"
+        ],
+        "prerequisites": [
+          "arrays",
+          "for-loops"
+        ]
+      },
+      {
+        "slug": "wizards-and-warriors-2",
+        "name": "Wizards and Warriors 2.0",
+        "uuid": "3f728065-98d8-472a-a84c-290f05ab1e58",
+        "concepts": [
+          "method-overloading",
+          "named-arguments",
+          "optional-parameters"
+        ],
+        "prerequisites": [
+          "classes",
+          "constructors",
+          "enums",
+          "properties",
+          "strings"
+        ]
+      },
+      {
+        "slug": "red-vs-blue-darwin-style",
+        "name": "Red vs. Blue: Darwin Style",
+        "uuid": "dcfd75d2-8264-4445-a95b-718867ec5eb4",
+        "concepts": [
+          "namespaces"
+        ],
+        "prerequisites": [
+          "classes",
+          "inheritance",
+          "nested-types"
+        ]
+      },
+      {
+        "slug": "remote-control-cleanup",
+        "name": "Remote Control Cleanup",
+        "uuid": "694cbd8d-677d-4052-960e-69386463a94b",
+        "concepts": [
+          "nested-types"
+        ],
+        "prerequisites": [
+          "classes",
+          "enums",
+          "interfaces",
+          "properties",
+          "structs"
+        ]
+      },
+      {
+        "slug": "tim-from-marketing",
+        "name": "Tim from Marketing",
+        "uuid": "370e7e54-6a96-11ea-bc55-0242ac130003",
+        "concepts": [
+          "nullability"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "memory-allocation",
+          "strings"
+        ]
+      },
+      {
+        "slug": "cars-assemble",
+        "name": "Cars, Assemble!",
+        "uuid": "93fbc7cf-3a7e-4450-ad22-e30129c36bb9",
+        "concepts": [
+          "if-statements",
+          "numbers"
+        ],
+        "prerequisites": [
+          "basics"
+        ]
+      },
+      {
+        "slug": "developer-privileges",
+        "name": "Developer Privileges",
+        "uuid": "a9c3a1c9-19ee-45b2-8189-57e15870a051",
+        "concepts": [
+          "object-initializers"
+        ],
+        "prerequisites": [
+          "constructors",
+          "dictionaries",
+          "properties"
+        ]
+      },
+      {
+        "slug": "hyperia-forex",
+        "name": "Hyperia Forex",
+        "uuid": "555cf3ae-d9b0-446f-8e2d-70a81aceab49",
+        "concepts": [
+          "operator-overloading"
+        ],
+        "prerequisites": [
+          "equality",
+          "floating-point-numbers",
+          "method-overloading"
+        ]
+      },
+      {
+        "slug": "hyperinflation-hits-hyperia",
+        "name": "Hyperinflation Hits Hyperia",
+        "uuid": "16f760c1-29b8-4c82-a085-9b4d81002c62",
+        "concepts": [
+          "overflow"
+        ],
+        "prerequisites": [
+          "exceptions",
+          "floating-point-numbers",
+          "integral-numbers",
+          "strings"
+        ]
+      },
+      {
+        "slug": "building-telemetry",
+        "name": "Building Telemetry",
+        "uuid": "f5c259fd-a404-432f-922d-781bde34fe08",
+        "concepts": [
+          "parameters"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "constructors",
+          "named-arguments",
+          "numbers",
+          "strings"
+        ]
+      },
+      {
+        "slug": "weighing-machine",
+        "name": "Weighing Machine",
+        "uuid": "978bcc16-0c49-4328-92e9-79f6204ce350",
+        "concepts": [
+          "properties"
+        ],
+        "prerequisites": [
+          "classes",
+          "enums",
+          "exceptions",
+          "floating-point-numbers",
+          "numbers"
+        ]
+      },
+      {
+        "slug": "roll-the-die",
+        "name": "Roll the Die!",
+        "uuid": "d8a43f1e-4ed0-4015-8307-fba1d9cdd117",
+        "concepts": [
+          "randomness"
+        ],
+        "prerequisites": [
+          "numbers"
+        ]
+      },
+      {
+        "slug": "parsing-log-files",
+        "name": "Parsing Log Files",
+        "uuid": "c63bb75d-51bd-4d5d-b37d-88e53ee0da69",
+        "concepts": [
+          "regular-expressions"
+        ],
+        "prerequisites": [
+          "arrays",
+          "for-loops",
+          "strings",
+          "string-interpolation",
+          "verbatim-strings"
+        ]
+      },
+      {
+        "slug": "object-relational-mapping",
+        "name": "Object Relational Mapping",
+        "uuid": "e99221eb-eecb-4746-9ef6-cc62650e41e1",
+        "concepts": [
+          "resource-cleanup"
+        ],
+        "prerequisites": [
+          "exceptions",
+          "inheritance"
+        ]
+      },
+      {
+        "slug": "orm-in-one-go",
+        "name": "Orm in One Go",
+        "uuid": "1c23e163-ceca-4cce-87ec-2e016db1262b",
+        "concepts": [
+          "resource-lifetime"
+        ],
+        "prerequisites": [
+          "resource-cleanup"
+        ]
+      },
+      {
+        "slug": "high-school-sweethearts",
+        "name": "High School Sweethearts",
+        "uuid": "eb435600-f983-4d55-a2c8-ef8b122334a0",
+        "concepts": [
+          "string-formatting",
+          "verbatim-strings"
+        ],
+        "prerequisites": [
+          "const-readonly",
+          "inheritance",
+          "string-builder",
+          "strings",
+          "time",
+          "varargs"
+        ]
+      },
+      {
+        "slug": "log-levels",
+        "name": "Log Levels",
+        "uuid": "eda235a5-37de-4fb6-a5c5-cf7aa2309987",
+        "concepts": [
+          "strings"
+        ],
+        "prerequisites": [
+          "basics"
+        ]
+      },
+      {
+        "slug": "land-grab-in-space",
+        "name": "Land Grab in Space",
+        "uuid": "1f43f015-fb34-49f6-bc77-7ab2234d90f2",
+        "concepts": [
+          "structs"
+        ],
+        "prerequisites": [
+          "classes",
+          "inheritance",
+          "numbers",
+          "sets",
+          "integral-numbers"
+        ]
+      },
+      {
+        "slug": "football-match-reports",
+        "name": "Football Match Reports",
+        "uuid": "eb9faaec-9754-4df1-8eb1-09ca0ad94665",
+        "concepts": [
+          "switch-statements"
+        ],
+        "prerequisites": [
+          "classes",
+          "inheritance"
+        ]
+      },
+      {
+        "slug": "beauty-salon-goes-global",
+        "name": "Beauty Salon Goes Global",
+        "uuid": "61dd2e1c-94bb-4c92-95ad-6460a7677884",
+        "concepts": [
+          "time",
+          "timezone"
+        ],
+        "prerequisites": [
+          "if-statements",
+          "datetimes",
+          "strings",
+          "switch-statements"
+        ]
+      },
+      {
+        "slug": "phone-number-analysis",
+        "name": "Phone Number Analysis",
+        "uuid": "8bb88ab5-3cde-4ebd-8eef-03323ebfd700",
+        "concepts": [
+          "tuples"
+        ],
+        "prerequisites": [
+          "strings"
+        ]
+      },
+      {
+        "slug": "instruments-of-texas",
+        "name": "Instruments of Texas",
+        "uuid": "1be577b0-95db-4c09-aff4-ddc68fb7520d",
+        "concepts": [
+          "user-defined-exceptions",
+          "exception-filtering"
+        ],
+        "prerequisites": [
+          "exceptions",
+          "inheritance",
+          "strings",
+          "if-statements",
+          "overflow",
+          "integral-numbers"
+        ]
+      }
+    ],
     "practice": [
       {
         "slug": "hello-world",

From 71308e9ab0f6788139f1d4e467c84f0764b83c73 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:51 +0100
Subject: [PATCH 310/327] [v3] Add wip status to concept exercises in
 config.json

---
 config.json | 123 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 82 insertions(+), 41 deletions(-)

diff --git a/config.json b/config.json
index 393af91a14..151e271707 100644
--- a/config.json
+++ b/config.json
@@ -29,7 +29,8 @@
           "booleans",
           "classes",
           "if-statements"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "lucians-luscious-lasagna",
@@ -38,7 +39,8 @@
         "concepts": [
           "basics"
         ],
-        "prerequisites": []
+        "prerequisites": [],
+        "status": "wip"
       },
       {
         "slug": "annalyns-infiltration",
@@ -49,7 +51,8 @@
         ],
         "prerequisites": [
           "basics"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "secure-munchester-united",
@@ -62,7 +65,8 @@
           "exceptions",
           "inheritance",
           "numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "squeaky-clean",
@@ -76,7 +80,8 @@
           "if-statements",
           "for-loops",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "elons-toys",
@@ -89,7 +94,8 @@
           "if-statements",
           "numbers",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "authentication-system",
@@ -108,7 +114,8 @@
           "nested-types",
           "object-initializers",
           "properties"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "need-for-speed",
@@ -122,7 +129,8 @@
           "if-statements",
           "numbers",
           "while-loops"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "booking-up-for-beauty",
@@ -135,7 +143,8 @@
           "classes",
           "numbers",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "international-calling-connoisseur",
@@ -149,7 +158,8 @@
           "generic-types",
           "strings",
           "indexers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "logs-logs-logs",
@@ -161,7 +171,8 @@
         "prerequisites": [
           "strings",
           "switch-statements"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "faceid-2",
@@ -178,7 +189,8 @@
           "inheritance",
           "interfaces",
           "lists"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "calculator-conundrum",
@@ -191,7 +203,8 @@
           "inheritance",
           "nullability",
           "switch-statements"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "the-weather-in-deather",
@@ -212,7 +225,8 @@
           "exceptions",
           "properties",
           "switch-statements"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "attack-of-the-trolls",
@@ -226,7 +240,8 @@
           "bit-manipulation",
           "enums",
           "integral-numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "interest-is-interesting",
@@ -240,7 +255,8 @@
         "prerequisites": [
           "if-statements",
           "numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "wizards-and-warriors",
@@ -255,7 +271,8 @@
           "if-statements",
           "constructors",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "hyper-optimized-telemetry",
@@ -267,7 +284,8 @@
         "prerequisites": [
           "arrays",
           "numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "remote-control-competition",
@@ -281,7 +299,8 @@
           "classes",
           "lists",
           "properties"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "tracks-on-tracks-on-tracks",
@@ -294,7 +313,8 @@
         "prerequisites": [
           "arrays",
           "for-loops"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "wizards-and-warriors-2",
@@ -311,7 +331,8 @@
           "enums",
           "properties",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "red-vs-blue-darwin-style",
@@ -324,7 +345,8 @@
           "classes",
           "inheritance",
           "nested-types"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "remote-control-cleanup",
@@ -339,7 +361,8 @@
           "interfaces",
           "properties",
           "structs"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "tim-from-marketing",
@@ -352,7 +375,8 @@
           "if-statements",
           "memory-allocation",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "cars-assemble",
@@ -364,7 +388,8 @@
         ],
         "prerequisites": [
           "basics"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "developer-privileges",
@@ -377,7 +402,8 @@
           "constructors",
           "dictionaries",
           "properties"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "hyperia-forex",
@@ -390,7 +416,8 @@
           "equality",
           "floating-point-numbers",
           "method-overloading"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "hyperinflation-hits-hyperia",
@@ -404,7 +431,8 @@
           "floating-point-numbers",
           "integral-numbers",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "building-telemetry",
@@ -419,7 +447,8 @@
           "named-arguments",
           "numbers",
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "weighing-machine",
@@ -434,7 +463,8 @@
           "exceptions",
           "floating-point-numbers",
           "numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "roll-the-die",
@@ -445,7 +475,8 @@
         ],
         "prerequisites": [
           "numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "parsing-log-files",
@@ -460,7 +491,8 @@
           "strings",
           "string-interpolation",
           "verbatim-strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "object-relational-mapping",
@@ -472,7 +504,8 @@
         "prerequisites": [
           "exceptions",
           "inheritance"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "orm-in-one-go",
@@ -483,7 +516,8 @@
         ],
         "prerequisites": [
           "resource-cleanup"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "high-school-sweethearts",
@@ -500,7 +534,8 @@
           "strings",
           "time",
           "varargs"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "log-levels",
@@ -511,7 +546,8 @@
         ],
         "prerequisites": [
           "basics"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "land-grab-in-space",
@@ -526,7 +562,8 @@
           "numbers",
           "sets",
           "integral-numbers"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "football-match-reports",
@@ -538,7 +575,8 @@
         "prerequisites": [
           "classes",
           "inheritance"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "beauty-salon-goes-global",
@@ -553,7 +591,8 @@
           "datetimes",
           "strings",
           "switch-statements"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "phone-number-analysis",
@@ -564,7 +603,8 @@
         ],
         "prerequisites": [
           "strings"
-        ]
+        ],
+        "status": "wip"
       },
       {
         "slug": "instruments-of-texas",
@@ -581,7 +621,8 @@
           "if-statements",
           "overflow",
           "integral-numbers"
-        ]
+        ],
+        "status": "wip"
       }
     ],
     "practice": [

From 755503bfc549ee58a23b784d257f6b8e9e62311c Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:51 +0100
Subject: [PATCH 311/327] [v3] Add concepts to config.json

---
 config.json | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 417 insertions(+), 1 deletion(-)

diff --git a/config.json b/config.json
index 151e271707..d683c03d58 100644
--- a/config.json
+++ b/config.json
@@ -2031,5 +2031,421 @@
       "point-mutations",
       "counter"
     ]
-  }
+  },
+  "concepts": [
+    {
+      "uuid": "efc1a32a-ebea-45ab-8c0b-5b512717abc0",
+      "slug": "arrays",
+      "name": "Arrays",
+      "blurb": "TODO: add blurb for arrays concept"
+    },
+    {
+      "uuid": "06a39e16-780f-4d44-811e-53ebf2fdf6d5",
+      "slug": "attributes",
+      "name": "Attributes",
+      "blurb": "TODO: add blurb for attributes concept"
+    },
+    {
+      "uuid": "2eb4a463-355f-46ef-ac55-a75ec5afdf86",
+      "slug": "basics",
+      "name": "Basics",
+      "blurb": "TODO: add blurb for basics concept"
+    },
+    {
+      "uuid": "83226d8e-9d8b-4223-82ad-6d251f519a49",
+      "slug": "bit-manipulation",
+      "name": "Bit Manipulation",
+      "blurb": "TODO: add blurb for bit-manipulation concept"
+    },
+    {
+      "uuid": "64a2670d-f61a-419f-8623-7116bad8e8a7",
+      "slug": "booleans",
+      "name": "Booleans",
+      "blurb": "TODO: add blurb for booleans concept"
+    },
+    {
+      "uuid": "e3b507b0-d2c3-4791-9c6e-6a40bdb4ec1a",
+      "slug": "casting",
+      "name": "Casting",
+      "blurb": "TODO: add blurb for casting concept"
+    },
+    {
+      "uuid": "352db7e4-c47c-42cf-a290-74e42fadc6ff",
+      "slug": "chars",
+      "name": "Chars",
+      "blurb": "TODO: add blurb for chars concept"
+    },
+    {
+      "uuid": "5b2f9bbb-079c-47fd-9ba6-0c6469e547cb",
+      "slug": "classes",
+      "name": "Classes",
+      "blurb": "TODO: add blurb for classes concept"
+    },
+    {
+      "uuid": "2c1ac74e-cec8-4616-a1c4-a08ef9f3f926",
+      "slug": "compound-assignment",
+      "name": "Compound Assignment",
+      "blurb": "TODO: add blurb for compound-assignment concept"
+    },
+    {
+      "uuid": "43820de3-174a-41a3-9fc0-d7a6f0c393aa",
+      "slug": "ternary-operators",
+      "name": "Conditionals Ternary",
+      "blurb": "TODO: add blurb for ternary-operators concept"
+    },
+    {
+      "uuid": "b29bc90a-65ae-4984-b7de-17debee7fc5f",
+      "slug": "const-readonly",
+      "name": "Const Readonly",
+      "blurb": "TODO: add blurb for const-readonly concept"
+    },
+    {
+      "uuid": "0ae08bee-1252-4d21-ae47-4952a1ab03b5",
+      "slug": "constants",
+      "name": "Constants",
+      "blurb": "TODO: add blurb for constants concept"
+    },
+    {
+      "uuid": "250f7606-f01d-4713-8e3e-1b1056a6b790",
+      "slug": "constructors",
+      "name": "Constructors",
+      "blurb": "TODO: add blurb for constructors concept"
+    },
+    {
+      "uuid": "bed44bba-b5a5-43e7-a548-b17812a6f536",
+      "slug": "datetimes",
+      "name": "Datetimes",
+      "blurb": "TODO: add blurb for datetimes concept"
+    },
+    {
+      "uuid": "c710b7f8-226f-4cc0-8a8f-b125cebb13fc",
+      "slug": "defensive-copying",
+      "name": "Defensive Copying",
+      "blurb": "TODO: add blurb for defensive-copying concept"
+    },
+    {
+      "uuid": "3af88acb-1487-4554-8715-089d7dda1199",
+      "slug": "dictionaries",
+      "name": "Dictionaries",
+      "blurb": "TODO: add blurb for dictionaries concept"
+    },
+    {
+      "uuid": "5b04ddb3-54ff-479f-a525-fb4f117d5c34",
+      "slug": "do-while-loops",
+      "name": "Do While Loops",
+      "blurb": "TODO: add blurb for do-while-loops concept"
+    },
+    {
+      "uuid": "d5b628d9-ac64-4eeb-91c7-f2dcff798b31",
+      "slug": "enums",
+      "name": "Enums",
+      "blurb": "TODO: add blurb for enums concept"
+    },
+    {
+      "uuid": "08632727-cfae-4c5b-b53f-f04ba35ce4ed",
+      "slug": "equality",
+      "name": "Equality",
+      "blurb": "TODO: add blurb for equality concept"
+    },
+    {
+      "uuid": "d3f5d61c-6bed-46ef-be21-cf7fdc07d4f7",
+      "slug": "exception-filtering",
+      "name": "Exception Filtering",
+      "blurb": "TODO: add blurb for exception-filtering concept"
+    },
+    {
+      "uuid": "6a322f90-1428-4ced-ba8c-cdcadf8914bd",
+      "slug": "exceptions",
+      "name": "Exceptions",
+      "blurb": "TODO: add blurb for exceptions concept"
+    },
+    {
+      "uuid": "c82d74c8-fbe1-42ab-be71-b1f524f28bf6",
+      "slug": "explicit-casts",
+      "name": "Explicit Casts",
+      "blurb": "TODO: add blurb for explicit-casts concept"
+    },
+    {
+      "uuid": "8e69833b-9668-4ed1-bfdd-d3c90fe4d9a4",
+      "slug": "expression-bodied-members",
+      "name": "Expression Bodied Members",
+      "blurb": "TODO: add blurb for expression-bodied-members concept"
+    },
+    {
+      "uuid": "0d0ce715-a7f2-42f4-b97b-54ba99b4df73",
+      "slug": "flag-enums",
+      "name": "Flag Enums",
+      "blurb": "TODO: add blurb for flag-enums concept"
+    },
+    {
+      "uuid": "05cd97a1-fedb-40c1-9f73-3a47d3f8690d",
+      "slug": "floating-point-numbers",
+      "name": "Floating Point Numbers",
+      "blurb": "TODO: add blurb for floating-point-numbers concept"
+    },
+    {
+      "uuid": "bd406da5-7a16-4487-a820-ce7ef5f1066b",
+      "slug": "for-loops",
+      "name": "For Loops",
+      "blurb": "TODO: add blurb for for-loops concept"
+    },
+    {
+      "uuid": "a352e32f-2e90-43ba-94c3-f22dc985e10a",
+      "slug": "foreach-loops",
+      "name": "Foreach Loops",
+      "blurb": "TODO: add blurb for foreach-loops concept"
+    },
+    {
+      "uuid": "555dc4c4-b30e-4928-a52e-336b05c26fca",
+      "slug": "generic-types",
+      "name": "Generic Types",
+      "blurb": "TODO: add blurb for generic-types concept"
+    },
+    {
+      "uuid": "4466e33e-dcd2-4b1f-9d9d-2c4315bf5188",
+      "slug": "if-statements",
+      "name": "If Statements",
+      "blurb": "TODO: add blurb for if-statements concept"
+    },
+    {
+      "uuid": "760a9811-a77f-4022-bc62-2a84dfbddbfc",
+      "slug": "indexers",
+      "name": "Indexers",
+      "blurb": "TODO: add blurb for indexers concept"
+    },
+    {
+      "uuid": "4725bc7b-481a-4ba2-951d-e7fa42c5b0c3",
+      "slug": "inheritance",
+      "name": "Inheritance",
+      "blurb": "TODO: add blurb for inheritance concept"
+    },
+    {
+      "uuid": "0b793025-5434-4c3d-ab72-67578669529f",
+      "slug": "integral-numbers",
+      "name": "Integral Numbers",
+      "blurb": "TODO: add blurb for integral-numbers concept"
+    },
+    {
+      "uuid": "10b71949-a188-481a-8c24-04a9c20c1530",
+      "slug": "interfaces",
+      "name": "Interfaces",
+      "blurb": "TODO: add blurb for interfaces concept"
+    },
+    {
+      "uuid": "dd7bf404-59af-4ae6-895b-5d04cdc8ecaa",
+      "slug": "lists",
+      "name": "Lists",
+      "blurb": "TODO: add blurb for lists concept"
+    },
+    {
+      "uuid": "a93a154c-4706-4c01-8ece-b5504ba3378d",
+      "slug": "memory-allocation",
+      "name": "Memory Allocation",
+      "blurb": "TODO: add blurb for memory-allocation concept"
+    },
+    {
+      "uuid": "e4c0bba5-e08b-426a-bccf-0f0fb375c2ad",
+      "slug": "method-overloading",
+      "name": "Method Overloading",
+      "blurb": "TODO: add blurb for method-overloading concept"
+    },
+    {
+      "uuid": "3b67cb8b-bcd3-4d34-ad4c-8e2009c3e6b5",
+      "slug": "named-arguments",
+      "name": "Named Arguments",
+      "blurb": "TODO: add blurb for named-arguments concept"
+    },
+    {
+      "uuid": "944d243a-65bc-4a52-97e8-b692a8419d04",
+      "slug": "namespaces",
+      "name": "Namespaces",
+      "blurb": "TODO: add blurb for namespaces concept"
+    },
+    {
+      "uuid": "339dce38-c4b6-423d-9b66-88fed35408d4",
+      "slug": "nested-types",
+      "name": "Nested Types",
+      "blurb": "TODO: add blurb for nested-types concept"
+    },
+    {
+      "uuid": "f66d4f26-ebd8-41d0-b79e-05858491e035",
+      "slug": "nullability",
+      "name": "Nullability",
+      "blurb": "TODO: add blurb for nullability concept"
+    },
+    {
+      "uuid": "b9a421b2-c5ff-4213-bd6d-b886da31ea0d",
+      "slug": "numbers",
+      "name": "Numbers",
+      "blurb": "TODO: add blurb for numbers concept"
+    },
+    {
+      "uuid": "9b50d5ee-7b68-46e3-9c3b-893c3a83110f",
+      "slug": "object-initializers",
+      "name": "Object Initializers",
+      "blurb": "TODO: add blurb for object-initializers concept"
+    },
+    {
+      "uuid": "3b510fdc-2975-41e4-acc5-c6b3780acf50",
+      "slug": "operator-overloading",
+      "name": "Operator Overloading",
+      "blurb": "TODO: add blurb for operator-overloading concept"
+    },
+    {
+      "uuid": "cddf1b02-6dcd-4ef0-9847-a2cd35abdb80",
+      "slug": "optional-parameters",
+      "name": "Optional Parameters",
+      "blurb": "TODO: add blurb for optional-parameters concept"
+    },
+    {
+      "uuid": "9f993d9a-144c-45fe-ab09-e368b5be2e6c",
+      "slug": "ordering",
+      "name": "Ordering",
+      "blurb": "TODO: add blurb for ordering concept"
+    },
+    {
+      "uuid": "a9ea7864-bfc7-49ce-815b-32d018627fe9",
+      "slug": "overflow",
+      "name": "Overflow",
+      "blurb": "TODO: add blurb for overflow concept"
+    },
+    {
+      "uuid": "83414ea8-0335-485c-a826-95c88a532d65",
+      "slug": "parameters",
+      "name": "Parameters",
+      "blurb": "TODO: add blurb for parameters concept"
+    },
+    {
+      "uuid": "7149c281-8b8c-42a2-a534-7bc5553cbbce",
+      "slug": "properties",
+      "name": "Properties",
+      "blurb": "TODO: add blurb for properties concept"
+    },
+    {
+      "uuid": "b71dc153-1cb0-4b82-ab5f-d896d6f1f7ed",
+      "slug": "randomness",
+      "name": "Randomness",
+      "blurb": "TODO: add blurb for randomness concept"
+    },
+    {
+      "uuid": "34e99b87-8862-47a7-87d3-621e1db47e5c",
+      "slug": "readonly-collections",
+      "name": "Readonly Collections",
+      "blurb": "TODO: add blurb for readonly-collections concept"
+    },
+    {
+      "uuid": "3c67b33f-e2a6-45e9-b4c4-456044e3c6ef",
+      "slug": "regular-expressions",
+      "name": "Regular Expressions",
+      "blurb": "TODO: add blurb for regular-expressions concept"
+    },
+    {
+      "uuid": "726f35e6-8af7-4279-b3bc-5299e1b7c182",
+      "slug": "resource-cleanup",
+      "name": "Resource Cleanup",
+      "blurb": "TODO: add blurb for resource-cleanup concept"
+    },
+    {
+      "uuid": "64ef0e6d-ca7a-4a3e-81a7-e66766615a9b",
+      "slug": "resource-lifetime",
+      "name": "Resource Lifetime",
+      "blurb": "TODO: add blurb for resource-lifetime concept"
+    },
+    {
+      "uuid": "d38a4651-09d2-47e5-8a18-9bcb6f3bfa0b",
+      "slug": "sets",
+      "name": "Sets",
+      "blurb": "TODO: add blurb for sets concept"
+    },
+    {
+      "uuid": "c1fcce17-0cbb-410e-8281-698606d73690",
+      "slug": "string-builder",
+      "name": "String Builder",
+      "blurb": "TODO: add blurb for string-builder concept"
+    },
+    {
+      "uuid": "7262549b-0bb3-4650-af34-e655c6ec59c2",
+      "slug": "string-formatting",
+      "name": "String Formatting",
+      "blurb": "TODO: add blurb for string-formatting concept"
+    },
+    {
+      "uuid": "df01147e-eac9-4df8-be9d-7bd81561a3c5",
+      "slug": "string-interpolation",
+      "name": "String Interpolation",
+      "blurb": "TODO: add blurb for string-interpolation concept"
+    },
+    {
+      "uuid": "fe39a4ab-e760-4e71-804e-2937ecc52b4d",
+      "slug": "strings",
+      "name": "Strings",
+      "blurb": "TODO: add blurb for strings concept"
+    },
+    {
+      "uuid": "b9a177bc-b815-4e85-9c0f-b84eb059500d",
+      "slug": "structs",
+      "name": "Structs",
+      "blurb": "TODO: add blurb for structs concept"
+    },
+    {
+      "uuid": "bc342654-6ebc-46fd-8148-eef2c8477a15",
+      "slug": "switch-expressions",
+      "name": "Switch Expressions",
+      "blurb": "TODO: add blurb for switch-expressions concept"
+    },
+    {
+      "uuid": "f57713c2-ddf3-4e71-802b-b24b552db609",
+      "slug": "switch-statements",
+      "name": "Switch Statements",
+      "blurb": "TODO: add blurb for switch-statements concept"
+    },
+    {
+      "uuid": "58d5caa7-1683-44e0-a62f-1564ac6959ab",
+      "slug": "throw-expressions",
+      "name": "Throw Expressions",
+      "blurb": "TODO: add blurb for throw-expressions concept"
+    },
+    {
+      "uuid": "050e789f-d318-41df-b2cc-f386ccf349dc",
+      "slug": "time",
+      "name": "Time",
+      "blurb": "TODO: add blurb for time concept"
+    },
+    {
+      "uuid": "3b83bdcc-de0b-43f7-b8f1-41fa9c656fb1",
+      "slug": "timezone",
+      "name": "Timezone",
+      "blurb": "TODO: add blurb for timezone concept"
+    },
+    {
+      "uuid": "86848fc2-c1ef-44ce-b099-86feabbbc7c9",
+      "slug": "tuples",
+      "name": "Tuples",
+      "blurb": "TODO: add blurb for tuples concept"
+    },
+    {
+      "uuid": "a625c3c3-7299-4426-99e5-f2c850479a29",
+      "slug": "user-defined-exceptions",
+      "name": "User Defined Exceptions",
+      "blurb": "TODO: add blurb for user-defined-exceptions concept"
+    },
+    {
+      "uuid": "1f78e26c-14d1-402e-a3cd-c786f8b1eec2",
+      "slug": "varargs",
+      "name": "Varargs",
+      "blurb": "TODO: add blurb for varargs concept"
+    },
+    {
+      "uuid": "6d85366c-7767-4d6a-af08-4cee5db801ca",
+      "slug": "verbatim-strings",
+      "name": "Verbatim Strings",
+      "blurb": "TODO: add blurb for verbatim-strings concept"
+    },
+    {
+      "uuid": "5442d5da-f74e-4793-97ee-97ddc09d4942",
+      "slug": "while-loops",
+      "name": "While Loops",
+      "blurb": "TODO: add blurb for while-loops concept"
+    }
+  ]
 }

From 53a39f91b07e72d3f9c0c56a62597e309a7a7468 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:51 +0100
Subject: [PATCH 312/327] [v3] Add key features to config.json

---
 config.json | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/config.json b/config.json
index d683c03d58..4e774cfa12 100644
--- a/config.json
+++ b/config.json
@@ -2447,5 +2447,37 @@
       "name": "While Loops",
       "blurb": "TODO: add blurb for while-loops concept"
     }
+  ],
+  "key_features": [
+    {
+      "icon": "features-oop",
+      "title": "Modern",
+      "content": "C# is a modern, fast-evolving language."
+    },
+    {
+      "icon": "features-strongly-typed",
+      "title": "Cross-platform",
+      "content": "C# runs on almost any platform and chipset."
+    },
+    {
+      "icon": "features-functional",
+      "title": "Multi-paradigm",
+      "content": "C# is primarily an object-oriented language, but also has lots of functional features."
+    },
+    {
+      "icon": "features-lazy",
+      "title": "General purpose",
+      "content": "C# can be used for a wide variety of workloads, like websites, console applications, and even games."
+    },
+    {
+      "icon": "features-declarative",
+      "title": "Tooling",
+      "content": "C# has excellent tooling, with linting and advanced refactoring options built-in."
+    },
+    {
+      "icon": "features-generic",
+      "title": "Documentation",
+      "content": "Documentation is excellent and exhaustive, making it easy to get started with C#."
+    }
   ]
 }

From 72cccbe170a91b1b3f754f58af9db77f276c9b4e Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:51 +0100
Subject: [PATCH 313/327] [v3] Add tags to config.json

---
 config.json | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/config.json b/config.json
index 4e774cfa12..ace8448150 100644
--- a/config.json
+++ b/config.json
@@ -2479,5 +2479,13 @@
       "title": "Documentation",
       "content": "Documentation is excellent and exhaustive, making it easy to get started with C#."
     }
+  ],
+  "tags": [
+    "compiles_to/bytecode",
+    "runtime/common_language_runtime",
+    "paradigm/declarative",
+    "paradigm/functional",
+    "paradigm/object_oriented",
+    "typing/static"
   ]
 }

From 92e6076e1be0db3e9c56d5201550421c262e4327 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:52 +0100
Subject: [PATCH 314/327] [v3] Add configlet CI workflow

---
 .github/workflows/configlet.yml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 .github/workflows/configlet.yml

diff --git a/.github/workflows/configlet.yml b/.github/workflows/configlet.yml
new file mode 100644
index 0000000000..c2bf9a4798
--- /dev/null
+++ b/.github/workflows/configlet.yml
@@ -0,0 +1,16 @@
+name: Configlet CI
+
+on: [push, pull_request, workflow_dispatch]
+
+jobs:
+  configlet:
+    runs-on: ubuntu-latest
+
+    steps:
+    - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f
+
+    - name: Fetch configlet
+      uses: exercism/github-actions/configlet-ci@main
+        
+    - name: Configlet Linter
+      run: configlet lint .

From 750a5e783016448579f0a8b2333a1c4f0b16c318 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:52 +0100
Subject: [PATCH 315/327] [v3] Update fetch-configlet script to work with
 configlet v3

---
 bin/fetch-configlet     | 91 +++++++++++++++++++++++++----------------
 bin/fetch-configlet.ps1 | 34 +++++++--------
 2 files changed, 74 insertions(+), 51 deletions(-)

diff --git a/bin/fetch-configlet b/bin/fetch-configlet
index f26caa3c7f..43f1c83cee 100755
--- a/bin/fetch-configlet
+++ b/bin/fetch-configlet
@@ -1,37 +1,58 @@
-#!/bin/bash
-
-LATEST=https://api.github.com/repos/exercism/configlet/releases/latest
-
-OS=$(
-case $(uname) in
-    (Darwin*)
-        echo "mac";;
-    (Linux*)
-        echo "linux";;
-    (*)
-        echo "linux";;
-esac)
-
-ARCH=$(
-case $(uname -m) in
-    (*64*)
-        echo 64bit;;
-    (*686*)
-        echo 32bit;;
-    (*386*)
-        echo 32bit;;
-    (*)
-        echo 64bit;;
-esac)
-
-FILENAME="configlet-${OS}-${ARCH}.tgz"
-
-if [ -z "${GITHUB_TOKEN}" ]
-then
-    HEADER=""
-else
-    HEADER="authorization: Bearer ${GITHUB_TOKEN}"
+#!/usr/bin/env bash
+
+set -eo pipefail
+
+readonly LATEST='https://api.github.com/repos/exercism/configlet/releases/latest'
+
+case "$(uname)" in
+  Darwin*)   os='mac'     ;;
+  Linux*)    os='linux'   ;;
+  Windows*)  os='windows' ;;
+  MINGW*)    os='windows' ;;
+  MSYS_NT-*) os='windows' ;;
+  *)         os='linux'   ;;
+esac
+
+case "${os}" in
+  windows*) ext='zip' ;;
+  *)        ext='tgz' ;;
+esac
+
+case "$(uname -m)" in
+  *64*)  arch='64bit' ;;
+  *686*) arch='32bit' ;;
+  *386*) arch='32bit' ;;
+  *)     arch='64bit' ;;
+esac
+
+curlopts=(
+  --silent
+  --show-error
+  --fail
+  --location
+  --retry 3
+)
+
+if [[ -n "${GITHUB_TOKEN}" ]]; then
+  curlopts+=(--header "authorization: Bearer ${GITHUB_TOKEN}")
 fi
 
-URL=$(curl --header $HEADER -s $LATEST | awk -v filename=$FILENAME '$1 ~ /browser_download_url/ && $2 ~ filename { print $2 }' | tr -d '"')
-curl --header $HEADER -s --location $URL | tar xz -C bin/
+suffix="${os}-${arch}.${ext}"
+
+get_download_url() {
+  curl "${curlopts[@]}" --header 'Accept: application/vnd.github.v3+json' "${LATEST}" |
+    grep "\"browser_download_url\": \".*/download/.*/configlet.*${suffix}\"$" |
+    cut -d'"' -f4
+}
+
+download_url="$(get_download_url)"
+output_dir="bin"
+output_path="${output_dir}/latest-configlet.${ext}"
+curl "${curlopts[@]}" --output "${output_path}" "${download_url}"
+
+case "${ext}" in
+  *zip) unzip "${output_path}" -d "${output_dir}"   ;;
+  *)    tar xzf "${output_path}" -C "${output_dir}" ;;
+esac
+
+rm -f "${output_path}"
diff --git a/bin/fetch-configlet.ps1 b/bin/fetch-configlet.ps1
index b0209054b4..291e57eb22 100644
--- a/bin/fetch-configlet.ps1
+++ b/bin/fetch-configlet.ps1
@@ -1,24 +1,26 @@
-Function DownloadUrl ([string] $FileName, $Headers) {
-    $latestUrl = "https://api.github.com/repos/exercism/configlet/releases/latest"
-    $json = Invoke-RestMethod -Headers $Headers -Uri $latestUrl
-    $json.assets | Where-Object { $_.browser_download_url -match $FileName } | Select-Object -ExpandProperty browser_download_url
-}
+$ErrorActionPreference = "Stop"
+$ProgressPreference = "SilentlyContinue"
 
-Function Headers {
-    If ($GITHUB_TOKEN) { $headers = @{ Authorization = "Bearer ${GITHUB_TOKEN}" } } Else { $headers = @{ } }
+$requestOpts = @{
+    Headers = If ($env:GITHUB_TOKEN) { @{ Authorization = "Bearer ${env:GITHUB_TOKEN}" } } Else { @{ } }
+    MaximumRetryCount = 3
+    RetryIntervalSec = 1
 }
 
-Function Arch {
-    If ([Environment]::Is64BitOperatingSystem) { "64bit" } Else { "32bit" }
+$arch = If ([Environment]::Is64BitOperatingSystem) { "64bit" } Else { "32bit" }
+$fileName = "configlet-windows-$arch.zip"
+
+Function Get-DownloadUrl {
+    $latestUrl = "https://api.github.com/repos/exercism/configlet/releases/latest"
+    Invoke-RestMethod -Uri $latestUrl -PreserveAuthorizationOnRedirect @requestOpts
+    | Select-Object -ExpandProperty assets
+    | Where-Object { $_.browser_download_url -match $FileName }
+    | Select-Object -ExpandProperty browser_download_url
 }
 
-$arch = Arch
-$headers = Headers
-$fileName = "configlet-windows-$arch.zip"
+$downloadUrl = Get-DownloadUrl
 $outputDirectory = "bin"
 $outputFile = Join-Path -Path $outputDirectory -ChildPath $fileName
-$zipUrl = DownloadUrl -FileName $fileName -Headers $headers
-
-Invoke-WebRequest -Headers $headers -Uri $zipUrl -OutFile $outputFile
+Invoke-WebRequest -Uri $downloadUrl -OutFile $outputFile @requestOpts
 Expand-Archive $outputFile -DestinationPath $outputDirectory -Force
-Remove-Item -Path $outputFile
\ No newline at end of file
+Remove-Item -Path $outputFile

From a1a496a8f4d11ba9f322483a53413c34ab7a6bcc Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:52 +0100
Subject: [PATCH 316/327] [v3] Add dependabot to keep GHA dependencies
 up-to-date

---
 .github/dependabot.yml | 9 +++++++++
 1 file changed, 9 insertions(+)
 create mode 100644 .github/dependabot.yml

diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000000..ed8f4a432b
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+version: 2
+
+updates:
+
+  # Keep dependencies for GitHub Actions up-to-date
+  - package-ecosystem: 'github-actions'
+    directory: '/'
+    schedule:
+      interval: 'daily'

From d6e00cbb9fb530b6c77d77fcae5483ad21529f99 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 14:33:53 +0100
Subject: [PATCH 317/327] [v3] Convert relative v3 links to absolute links

---
 .../concept/attack-of-the-trolls/.meta/design.md |  2 +-
 reference/implementing-a-concept-exercise.md     | 16 ++++++++--------
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/exercises/concept/attack-of-the-trolls/.meta/design.md b/exercises/concept/attack-of-the-trolls/.meta/design.md
index 1e1cf03db2..57feceaee5 100644
--- a/exercises/concept/attack-of-the-trolls/.meta/design.md
+++ b/exercises/concept/attack-of-the-trolls/.meta/design.md
@@ -43,4 +43,4 @@ This exercise could benefit from having an [analyzer][analyzer] that can comment
 [docs.microsoft.com-binary-notation]: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/integral-numeric-types#integer-literals
 [docs.microsoft.com-flagsattribute]: https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0
 [alanzucconi.com-enum-flags-and-bitwise-operators]: https://www.alanzucconi.com/2015/07/26/enum-flags-and-bitwise-operators/
-[concept-bitwise-manipulation]: ../../../../../reference/concepts/bitwise_manipulation.md
+[concept-bitwise-manipulation]: https://github.com/exercism/v3/blob/main/reference/concepts/bitwise_manipulation.md
diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md
index 50fa355346..97a4fdc849 100644
--- a/reference/implementing-a-concept-exercise.md
+++ b/reference/implementing-a-concept-exercise.md
@@ -128,15 +128,15 @@ If you have any questions regarding implementing the exercise, please post them
 [analyzer]: https://github.com/exercism/csharp-analyzer
 [representer]: https://github.com/exercism/csharp-representer
 [concept-exercises]: ../exercises/concept/README.md
-[how-to-implement-a-concept-exercise]: ../../../docs/maintainers/generic-how-to-implement-a-concept-exercise.md
-[docs-concept-exercises]: ../../../docs/concept-exercises.md
-[docs-rationale-for-v3]: ../../../docs/rationale-for-v3.md
-[docs-features-of-v3]: ../../../docs/features-of-v3.md
+[how-to-implement-a-concept-exercise]: https://github.com/exercism/v3/blob/main/docs/maintainers/generic-how-to-implement-a-concept-exercise.md
+[docs-concept-exercises]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md
+[docs-rationale-for-v3]: https://github.com/exercism/v3/blob/main/docs/rationale-for-v3.md
+[docs-features-of-v3]: https://github.com/exercism/v3/blob/main/docs/features-of-v3.md
 [anatomy-of-a-concept-exercise]: https://www.youtube.com/watch?v=gkbBqd7hPrA
 [concept-exercise-log-levels]: ../exercises/concept/log-levels
 [concept-exercise-booking-up-for-beauty]: ../exercises/concept/booking-up-for-beauty
 [concept-exercise-interest-is-interesting]: ../exercises/concept/interest-is-interesting
-[reference]: ../../../reference
+[reference]: https://github.com/exercism/v3/blob/main/reference
 [dotnet-format]: https://github.com/dotnet/format
 [allowing-fork-pr-changes]: https://help.github.com/en/github/collaborating-with-issues-and-pull-requests/allowing-changes-to-a-pull-request-branch-created-from-a-fork
 [implemented-exercises]: ../exercises/concept/README.md#implemented-exercises
@@ -153,9 +153,9 @@ If you have any questions regarding implementing the exercise, please post them
 [not-implemented-static]: ../exercises/concept/bird-watcher/BirdWatcher.cs#L12
 [not-implemented]: ../exercises/concept/bird-watcher/BirdWatcher.cs#L17
 [todo]: ../exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.cs
-[stub-file]: ../../../docs/concept-exercises.md#stub-implementation-file
-[tests-file]: ../../../docs/concept-exercises.md#tests-file
-[example-file]: ../../../docs/concept-exercises.md#example-implementation-file
+[stub-file]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md#stub-implementation-file
+[tests-file]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md#tests-file
+[example-file]: https://github.com/exercism/v3/blob/main/docs/concept-exercises.md#example-implementation-file
 [video-stub-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1171
 [video-tests-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=1255
 [video-example-file]: https://www.youtube.com/watch?v=gkbBqd7hPrA&t=781

From edd6ea8294d130bd43eb4a15dfa195576389e537 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Fri, 29 Jan 2021 16:27:34 +0100
Subject: [PATCH 318/327] [v3] Fix configlet CI workflow

---
 .github/workflows/configlet.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/configlet.yml b/.github/workflows/configlet.yml
index c2bf9a4798..c86ed0cf59 100644
--- a/.github/workflows/configlet.yml
+++ b/.github/workflows/configlet.yml
@@ -13,4 +13,4 @@ jobs:
       uses: exercism/github-actions/configlet-ci@main
         
     - name: Configlet Linter
-      run: configlet lint .
+      run: configlet lint

From a4d3bbade94a09b4b99f455cf765b170d5793fbe Mon Sep 17 00:00:00 2001
From: valentin-p <3833193+valentin-p@users.noreply.github.com>
Date: Tue, 2 Feb 2021 11:06:55 +0100
Subject: [PATCH 319/327] Use net5.0 to run the tests (#1485)

---
 .github/workflows/test.yml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 4ac35b630a..3a4fba6dbe 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -4,12 +4,12 @@ on: [push, pull_request]
 
 jobs:
   test:
-    runs-on: ubuntu-18.04
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout@5a4ac9002d0be2fb38bd78e4b4dbde5606d7042f # 2.3.4
       - uses: actions/setup-dotnet@51f68377c181a79065c61bd492bd49be4575c439 # 1.7.2
         with:
-          dotnet-version: "3.0.100"
+          dotnet-version: "5.0.102"
       - run: pwsh ./test.ps1
         env:
           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

From 0d8c01a81378fe9ec2faa49403d1ce9ebbe11e67 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Wed, 3 Feb 2021 16:06:49 +0100
Subject: [PATCH 320/327] Update status of track (#1487)

---
 config.json | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/config.json b/config.json
index ace8448150..8337bfee13 100644
--- a/config.json
+++ b/config.json
@@ -3,10 +3,10 @@
   "slug": "csharp",
   "active": true,
   "status": {
-    "concept_exercises": false,
-    "test_runner": false,
-    "representer": false,
-    "analyzer": false
+    "concept_exercises": true,
+    "test_runner": true,
+    "representer": true,
+    "analyzer": true
   },
   "blurb": "C# is a modern, object-oriented language with lots of great features, such as type-inference and async/await. The tooling is excellent, and there is extensive, well-written documentation.",
   "version": 3,

From 328798d26c5af34da140da160c9a2b25c7285a35 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Wed, 3 Feb 2021 16:07:03 +0100
Subject: [PATCH 321/327] Add tags (#1486)

---
 config.json | 22 ++++++++++++++++++----
 1 file changed, 18 insertions(+), 4 deletions(-)

diff --git a/config.json b/config.json
index 8337bfee13..4076a181b9 100644
--- a/config.json
+++ b/config.json
@@ -2481,11 +2481,25 @@
     }
   ],
   "tags": [
-    "compiles_to/bytecode",
-    "runtime/common_language_runtime",
-    "paradigm/declarative",
     "paradigm/functional",
+    "paradigm/imperative",
     "paradigm/object_oriented",
-    "typing/static"
+    "typing/static",
+    "typing/strong",
+    "execution_mode/compiled",
+    "platform/windows",
+    "platform/mac",
+    "platform/linux",
+    "platform/ios",
+    "platform/android",
+    "platform/web",
+    "runtime/clr",
+    "used_for/backends",
+    "used_for/cross_platform_development",
+    "used_for/frontends",
+    "used_for/games",
+    "used_for/guis",
+    "used_for/mobile",
+    "used_for/web_development"
   ]
 }

From 9adcf3915efb87a9ee4eebfd3af5d5884a911ec8 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Thu, 4 Feb 2021 08:18:48 +0100
Subject: [PATCH 322/327] Fix configlet lint (#1488)

---
 test.ps1 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test.ps1 b/test.ps1
index 6dc07a37d9..d54795e636 100644
--- a/test.ps1
+++ b/test.ps1
@@ -31,7 +31,7 @@ $exercisesDir = Resolve-Path "exercises"
 function Configlet-Lint {
     Write-Output "Linting config.json"
     Run-Command "./bin/fetch-configlet"
-    Run-Command "./bin/configlet lint ."
+    Run-Command "./bin/configlet lint"
 }
 
 function Build-Generators { 

From 54961c0a475a2e59e97236bc8bced3ace2f01537 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 9 Feb 2021 08:35:28 +0100
Subject: [PATCH 323/327] nuget: bump Microsoft.NET.Test.Sdk to 16.8.3 (#1491)

---
 .../concept/annalyns-infiltration/AnnalynsInfiltration.csproj   | 2 +-
 exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj | 2 +-
 exercises/concept/bird-watcher/BirdWatcher.csproj               | 2 +-
 .../concept/booking-up-for-beauty/BookingUpForBeauty.csproj     | 2 +-
 exercises/concept/cars-assemble/CarsAssemble.csproj             | 2 +-
 exercises/concept/elons-toys/ElonsToys.csproj                   | 2 +-
 .../interest-is-interesting/InterestIsInteresting.csproj        | 2 +-
 exercises/concept/log-levels/LogLevels.csproj                   | 2 +-
 exercises/concept/logs-logs-logs/LogsLogsLogs.csproj            | 2 +-
 .../lucians-luscious-lasagna/LuciansLusciousLasagna.csproj      | 2 +-
 exercises/concept/need-for-speed/NeedForSpeed.csproj            | 2 +-
 exercises/concept/tim-from-marketing/TimFromMarketing.csproj    | 2 +-
 .../concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj   | 2 +-
 .../concept/wizards-and-warriors/WizardsAndWarriors.csproj      | 2 +-
 14 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
+++ b/exercises/concept/annalyns-infiltration/AnnalynsInfiltration.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
+++ b/exercises/concept/attack-of-the-trolls/AttackOfTheTrolls.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/bird-watcher/BirdWatcher.csproj b/exercises/concept/bird-watcher/BirdWatcher.csproj
index 7965bd0632..a1ffc94452 100644
--- a/exercises/concept/bird-watcher/BirdWatcher.csproj
+++ b/exercises/concept/bird-watcher/BirdWatcher.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
+++ b/exercises/concept/booking-up-for-beauty/BookingUpForBeauty.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/cars-assemble/CarsAssemble.csproj b/exercises/concept/cars-assemble/CarsAssemble.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/cars-assemble/CarsAssemble.csproj
+++ b/exercises/concept/cars-assemble/CarsAssemble.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/elons-toys/ElonsToys.csproj b/exercises/concept/elons-toys/ElonsToys.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/elons-toys/ElonsToys.csproj
+++ b/exercises/concept/elons-toys/ElonsToys.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
+++ b/exercises/concept/interest-is-interesting/InterestIsInteresting.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/log-levels/LogLevels.csproj b/exercises/concept/log-levels/LogLevels.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/log-levels/LogLevels.csproj
+++ b/exercises/concept/log-levels/LogLevels.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
+++ b/exercises/concept/logs-logs-logs/LogsLogsLogs.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
+++ b/exercises/concept/lucians-luscious-lasagna/LuciansLusciousLasagna.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/need-for-speed/NeedForSpeed.csproj b/exercises/concept/need-for-speed/NeedForSpeed.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/need-for-speed/NeedForSpeed.csproj
+++ b/exercises/concept/need-for-speed/NeedForSpeed.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
index fead1729ca..dcdde3f1de 100644
--- a/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
+++ b/exercises/concept/tim-from-marketing/TimFromMarketing.csproj
@@ -6,7 +6,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
+++ b/exercises/concept/wizards-and-warriors-2/WizardsAndWarriors2.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   
diff --git a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
index 008d1fa438..b06e44aef0 100644
--- a/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
+++ b/exercises/concept/wizards-and-warriors/WizardsAndWarriors.csproj
@@ -5,7 +5,7 @@
   
 
   
-    
+    
     
     
   

From fbb11dea39a1530c28d441f8ca22771c1561ae79 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 9 Feb 2021 08:35:37 +0100
Subject: [PATCH 324/327] projects: bump target framework to net5.0 (#1490)

---
 exercises/practice/accumulate/Accumulate.csproj                 | 2 +-
 exercises/practice/acronym/Acronym.csproj                       | 2 +-
 exercises/practice/affine-cipher/AffineCipher.csproj            | 2 +-
 exercises/practice/all-your-base/AllYourBase.csproj             | 2 +-
 exercises/practice/allergies/Allergies.csproj                   | 2 +-
 exercises/practice/alphametics/Alphametics.csproj               | 2 +-
 exercises/practice/anagram/Anagram.csproj                       | 2 +-
 exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj    | 2 +-
 exercises/practice/atbash-cipher/AtbashCipher.csproj            | 2 +-
 exercises/practice/bank-account/BankAccount.csproj              | 2 +-
 exercises/practice/beer-song/BeerSong.csproj                    | 2 +-
 exercises/practice/binary-search-tree/BinarySearchTree.csproj   | 2 +-
 exercises/practice/binary-search/BinarySearch.csproj            | 2 +-
 exercises/practice/binary/Binary.csproj                         | 2 +-
 exercises/practice/bob/Bob.csproj                               | 2 +-
 exercises/practice/book-store/BookStore.csproj                  | 2 +-
 exercises/practice/bowling/Bowling.csproj                       | 2 +-
 exercises/practice/change/Change.csproj                         | 2 +-
 exercises/practice/circular-buffer/CircularBuffer.csproj        | 2 +-
 exercises/practice/clock/Clock.csproj                           | 2 +-
 exercises/practice/collatz-conjecture/CollatzConjecture.csproj  | 2 +-
 exercises/practice/complex-numbers/ComplexNumbers.csproj        | 2 +-
 exercises/practice/connect/Connect.csproj                       | 2 +-
 exercises/practice/crypto-square/CryptoSquare.csproj            | 2 +-
 exercises/practice/custom-set/CustomSet.csproj                  | 2 +-
 exercises/practice/darts/Darts.csproj                           | 2 +-
 exercises/practice/diamond/Diamond.csproj                       | 2 +-
 .../practice/difference-of-squares/DifferenceOfSquares.csproj   | 2 +-
 exercises/practice/diffie-hellman/DiffieHellman.csproj          | 2 +-
 exercises/practice/dnd-character/DndCharacter.csproj            | 2 +-
 exercises/practice/dominoes/Dominoes.csproj                     | 2 +-
 exercises/practice/dot-dsl/DotDsl.csproj                        | 2 +-
 exercises/practice/error-handling/ErrorHandling.csproj          | 2 +-
 exercises/practice/etl/Etl.csproj                               | 2 +-
 exercises/practice/flatten-array/FlattenArray.csproj            | 2 +-
 exercises/practice/food-chain/FoodChain.csproj                  | 2 +-
 exercises/practice/forth/Forth.csproj                           | 2 +-
 exercises/practice/gigasecond/Gigasecond.csproj                 | 2 +-
 exercises/practice/go-counting/GoCounting.csproj                | 2 +-
 exercises/practice/grade-school/GradeSchool.csproj              | 2 +-
 exercises/practice/grains/Grains.csproj                         | 2 +-
 exercises/practice/grep/Grep.csproj                             | 2 +-
 exercises/practice/hamming/Hamming.csproj                       | 2 +-
 exercises/practice/hangman/Hangman.csproj                       | 2 +-
 exercises/practice/hello-world/HelloWorld.csproj                | 2 +-
 exercises/practice/hexadecimal/Hexadecimal.csproj               | 2 +-
 exercises/practice/high-scores/HighScores.csproj                | 2 +-
 exercises/practice/house/House.csproj                           | 2 +-
 exercises/practice/isbn-verifier/IsbnVerifier.csproj            | 2 +-
 exercises/practice/isogram/Isogram.csproj                       | 2 +-
 .../practice/kindergarten-garden/KindergartenGarden.csproj      | 2 +-
 .../practice/largest-series-product/LargestSeriesProduct.csproj | 2 +-
 exercises/practice/leap/Leap.csproj                             | 2 +-
 exercises/practice/ledger/Ledger.csproj                         | 2 +-
 exercises/practice/linked-list/LinkedList.csproj                | 2 +-
 exercises/practice/list-ops/ListOps.csproj                      | 2 +-
 exercises/practice/luhn/Luhn.csproj                             | 2 +-
 exercises/practice/markdown/Markdown.csproj                     | 2 +-
 exercises/practice/matching-brackets/MatchingBrackets.csproj    | 2 +-
 exercises/practice/matrix/Matrix.csproj                         | 2 +-
 exercises/practice/meetup/Meetup.csproj                         | 2 +-
 exercises/practice/minesweeper/Minesweeper.csproj               | 2 +-
 exercises/practice/nth-prime/NthPrime.csproj                    | 2 +-
 exercises/practice/nucleotide-count/NucleotideCount.csproj      | 2 +-
 exercises/practice/ocr-numbers/OcrNumbers.csproj                | 2 +-
 exercises/practice/octal/Octal.csproj                           | 2 +-
 .../practice/palindrome-products/PalindromeProducts.csproj      | 2 +-
 exercises/practice/pangram/Pangram.csproj                       | 2 +-
 .../parallel-letter-frequency/ParallelLetterFrequency.csproj    | 2 +-
 exercises/practice/pascals-triangle/PascalsTriangle.csproj      | 2 +-
 exercises/practice/perfect-numbers/PerfectNumbers.csproj        | 2 +-
 exercises/practice/phone-number/PhoneNumber.csproj              | 2 +-
 exercises/practice/pig-latin/PigLatin.csproj                    | 2 +-
 exercises/practice/poker/Poker.csproj                           | 2 +-
 exercises/practice/pov/Pov.csproj                               | 2 +-
 exercises/practice/prime-factors/PrimeFactors.csproj            | 2 +-
 .../practice/protein-translation/ProteinTranslation.csproj      | 2 +-
 exercises/practice/proverb/Proverb.csproj                       | 2 +-
 .../practice/pythagorean-triplet/PythagoreanTriplet.csproj      | 2 +-
 exercises/practice/queen-attack/QueenAttack.csproj              | 2 +-
 exercises/practice/rail-fence-cipher/RailFenceCipher.csproj     | 2 +-
 exercises/practice/raindrops/Raindrops.csproj                   | 2 +-
 exercises/practice/rational-numbers/RationalNumbers.csproj      | 2 +-
 exercises/practice/react/React.csproj                           | 2 +-
 exercises/practice/rectangles/Rectangles.csproj                 | 2 +-
 exercises/practice/resistor-color-duo/ResistorColorDuo.csproj   | 2 +-
 exercises/practice/resistor-color-trio/ResistorColorTrio.csproj | 2 +-
 exercises/practice/resistor-color/ResistorColor.csproj          | 2 +-
 exercises/practice/rest-api/RestApi.csproj                      | 2 +-
 exercises/practice/reverse-string/ReverseString.csproj          | 2 +-
 exercises/practice/rna-transcription/RnaTranscription.csproj    | 2 +-
 exercises/practice/robot-name/RobotName.csproj                  | 2 +-
 exercises/practice/robot-simulator/RobotSimulator.csproj        | 2 +-
 exercises/practice/roman-numerals/RomanNumerals.csproj          | 2 +-
 exercises/practice/rotational-cipher/RotationalCipher.csproj    | 2 +-
 exercises/practice/run-length-encoding/RunLengthEncoding.csproj | 2 +-
 exercises/practice/saddle-points/SaddlePoints.csproj            | 2 +-
 exercises/practice/say/Say.csproj                               | 2 +-
 exercises/practice/scale-generator/ScaleGenerator.csproj        | 2 +-
 exercises/practice/scrabble-score/ScrabbleScore.csproj          | 2 +-
 exercises/practice/secret-handshake/SecretHandshake.csproj      | 2 +-
 exercises/practice/series/Series.csproj                         | 2 +-
 exercises/practice/sgf-parsing/SgfParsing.csproj                | 2 +-
 exercises/practice/sieve/Sieve.csproj                           | 2 +-
 exercises/practice/simple-cipher/SimpleCipher.csproj            | 2 +-
 exercises/practice/simple-linked-list/SimpleLinkedList.csproj   | 2 +-
 exercises/practice/space-age/SpaceAge.csproj                    | 2 +-
 exercises/practice/spiral-matrix/SpiralMatrix.csproj            | 2 +-
 exercises/practice/strain/Strain.csproj                         | 2 +-
 exercises/practice/sublist/Sublist.csproj                       | 2 +-
 exercises/practice/sum-of-multiples/SumOfMultiples.csproj       | 2 +-
 exercises/practice/tournament/Tournament.csproj                 | 2 +-
 exercises/practice/transpose/Transpose.csproj                   | 2 +-
 exercises/practice/tree-building/TreeBuilding.csproj            | 2 +-
 exercises/practice/triangle/Triangle.csproj                     | 2 +-
 exercises/practice/trinary/Trinary.csproj                       | 2 +-
 exercises/practice/twelve-days/TwelveDays.csproj                | 2 +-
 exercises/practice/two-bucket/TwoBucket.csproj                  | 2 +-
 exercises/practice/two-fer/TwoFer.csproj                        | 2 +-
 .../variable-length-quantity/VariableLengthQuantity.csproj      | 2 +-
 exercises/practice/word-count/WordCount.csproj                  | 2 +-
 exercises/practice/word-search/WordSearch.csproj                | 2 +-
 exercises/practice/wordy/Wordy.csproj                           | 2 +-
 exercises/practice/yacht/Yacht.csproj                           | 2 +-
 exercises/practice/zebra-puzzle/ZebraPuzzle.csproj              | 2 +-
 exercises/practice/zipper/Zipper.csproj                         | 2 +-
 generators/Generators.csproj                                    | 2 +-
 127 files changed, 127 insertions(+), 127 deletions(-)

diff --git a/exercises/practice/accumulate/Accumulate.csproj b/exercises/practice/accumulate/Accumulate.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/accumulate/Accumulate.csproj
+++ b/exercises/practice/accumulate/Accumulate.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/acronym/Acronym.csproj b/exercises/practice/acronym/Acronym.csproj
index 21842be6e6..971955d3b7 100644
--- a/exercises/practice/acronym/Acronym.csproj
+++ b/exercises/practice/acronym/Acronym.csproj
@@ -2,7 +2,7 @@
 
   
     
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/affine-cipher/AffineCipher.csproj b/exercises/practice/affine-cipher/AffineCipher.csproj
index 1db314bd6d..151f87cd64 100644
--- a/exercises/practice/affine-cipher/AffineCipher.csproj
+++ b/exercises/practice/affine-cipher/AffineCipher.csproj
@@ -2,7 +2,7 @@
 
   
     Exe
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/all-your-base/AllYourBase.csproj b/exercises/practice/all-your-base/AllYourBase.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/all-your-base/AllYourBase.csproj
+++ b/exercises/practice/all-your-base/AllYourBase.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/allergies/Allergies.csproj b/exercises/practice/allergies/Allergies.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/allergies/Allergies.csproj
+++ b/exercises/practice/allergies/Allergies.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/alphametics/Alphametics.csproj b/exercises/practice/alphametics/Alphametics.csproj
index d2ed92989d..fea812ef87 100644
--- a/exercises/practice/alphametics/Alphametics.csproj
+++ b/exercises/practice/alphametics/Alphametics.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/anagram/Anagram.csproj b/exercises/practice/anagram/Anagram.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/anagram/Anagram.csproj
+++ b/exercises/practice/anagram/Anagram.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj b/exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj
+++ b/exercises/practice/armstrong-numbers/ArmstrongNumbers.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/atbash-cipher/AtbashCipher.csproj b/exercises/practice/atbash-cipher/AtbashCipher.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/atbash-cipher/AtbashCipher.csproj
+++ b/exercises/practice/atbash-cipher/AtbashCipher.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/bank-account/BankAccount.csproj b/exercises/practice/bank-account/BankAccount.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/bank-account/BankAccount.csproj
+++ b/exercises/practice/bank-account/BankAccount.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/beer-song/BeerSong.csproj b/exercises/practice/beer-song/BeerSong.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/beer-song/BeerSong.csproj
+++ b/exercises/practice/beer-song/BeerSong.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/binary-search-tree/BinarySearchTree.csproj b/exercises/practice/binary-search-tree/BinarySearchTree.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/binary-search-tree/BinarySearchTree.csproj
+++ b/exercises/practice/binary-search-tree/BinarySearchTree.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/binary-search/BinarySearch.csproj b/exercises/practice/binary-search/BinarySearch.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/binary-search/BinarySearch.csproj
+++ b/exercises/practice/binary-search/BinarySearch.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/binary/Binary.csproj b/exercises/practice/binary/Binary.csproj
index a5ea09ee4e..01de85b07d 100644
--- a/exercises/practice/binary/Binary.csproj
+++ b/exercises/practice/binary/Binary.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/bob/Bob.csproj b/exercises/practice/bob/Bob.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/bob/Bob.csproj
+++ b/exercises/practice/bob/Bob.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/book-store/BookStore.csproj b/exercises/practice/book-store/BookStore.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/book-store/BookStore.csproj
+++ b/exercises/practice/book-store/BookStore.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/bowling/Bowling.csproj b/exercises/practice/bowling/Bowling.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/bowling/Bowling.csproj
+++ b/exercises/practice/bowling/Bowling.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/change/Change.csproj b/exercises/practice/change/Change.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/change/Change.csproj
+++ b/exercises/practice/change/Change.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/circular-buffer/CircularBuffer.csproj b/exercises/practice/circular-buffer/CircularBuffer.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/circular-buffer/CircularBuffer.csproj
+++ b/exercises/practice/circular-buffer/CircularBuffer.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/clock/Clock.csproj b/exercises/practice/clock/Clock.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/clock/Clock.csproj
+++ b/exercises/practice/clock/Clock.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/collatz-conjecture/CollatzConjecture.csproj b/exercises/practice/collatz-conjecture/CollatzConjecture.csproj
index e24fe6686a..901e6d95c5 100644
--- a/exercises/practice/collatz-conjecture/CollatzConjecture.csproj
+++ b/exercises/practice/collatz-conjecture/CollatzConjecture.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/complex-numbers/ComplexNumbers.csproj b/exercises/practice/complex-numbers/ComplexNumbers.csproj
index d22f790a82..530c71c117 100644
--- a/exercises/practice/complex-numbers/ComplexNumbers.csproj
+++ b/exercises/practice/complex-numbers/ComplexNumbers.csproj
@@ -2,7 +2,7 @@
 
   
     
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/connect/Connect.csproj b/exercises/practice/connect/Connect.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/connect/Connect.csproj
+++ b/exercises/practice/connect/Connect.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/crypto-square/CryptoSquare.csproj b/exercises/practice/crypto-square/CryptoSquare.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/crypto-square/CryptoSquare.csproj
+++ b/exercises/practice/crypto-square/CryptoSquare.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/custom-set/CustomSet.csproj b/exercises/practice/custom-set/CustomSet.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/custom-set/CustomSet.csproj
+++ b/exercises/practice/custom-set/CustomSet.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/darts/Darts.csproj b/exercises/practice/darts/Darts.csproj
index 0386d092c4..aa130abe47 100644
--- a/exercises/practice/darts/Darts.csproj
+++ b/exercises/practice/darts/Darts.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/diamond/Diamond.csproj b/exercises/practice/diamond/Diamond.csproj
index a9ce1b45ea..790726f5a9 100644
--- a/exercises/practice/diamond/Diamond.csproj
+++ b/exercises/practice/diamond/Diamond.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/difference-of-squares/DifferenceOfSquares.csproj b/exercises/practice/difference-of-squares/DifferenceOfSquares.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/difference-of-squares/DifferenceOfSquares.csproj
+++ b/exercises/practice/difference-of-squares/DifferenceOfSquares.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/diffie-hellman/DiffieHellman.csproj b/exercises/practice/diffie-hellman/DiffieHellman.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/diffie-hellman/DiffieHellman.csproj
+++ b/exercises/practice/diffie-hellman/DiffieHellman.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/dnd-character/DndCharacter.csproj b/exercises/practice/dnd-character/DndCharacter.csproj
index 0386d092c4..aa130abe47 100644
--- a/exercises/practice/dnd-character/DndCharacter.csproj
+++ b/exercises/practice/dnd-character/DndCharacter.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/dominoes/Dominoes.csproj b/exercises/practice/dominoes/Dominoes.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/dominoes/Dominoes.csproj
+++ b/exercises/practice/dominoes/Dominoes.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/dot-dsl/DotDsl.csproj b/exercises/practice/dot-dsl/DotDsl.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/dot-dsl/DotDsl.csproj
+++ b/exercises/practice/dot-dsl/DotDsl.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/error-handling/ErrorHandling.csproj b/exercises/practice/error-handling/ErrorHandling.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/error-handling/ErrorHandling.csproj
+++ b/exercises/practice/error-handling/ErrorHandling.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/etl/Etl.csproj b/exercises/practice/etl/Etl.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/etl/Etl.csproj
+++ b/exercises/practice/etl/Etl.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/flatten-array/FlattenArray.csproj b/exercises/practice/flatten-array/FlattenArray.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/flatten-array/FlattenArray.csproj
+++ b/exercises/practice/flatten-array/FlattenArray.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/food-chain/FoodChain.csproj b/exercises/practice/food-chain/FoodChain.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/food-chain/FoodChain.csproj
+++ b/exercises/practice/food-chain/FoodChain.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/forth/Forth.csproj b/exercises/practice/forth/Forth.csproj
index d2ed92989d..fea812ef87 100644
--- a/exercises/practice/forth/Forth.csproj
+++ b/exercises/practice/forth/Forth.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/gigasecond/Gigasecond.csproj b/exercises/practice/gigasecond/Gigasecond.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/gigasecond/Gigasecond.csproj
+++ b/exercises/practice/gigasecond/Gigasecond.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/go-counting/GoCounting.csproj b/exercises/practice/go-counting/GoCounting.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/go-counting/GoCounting.csproj
+++ b/exercises/practice/go-counting/GoCounting.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/grade-school/GradeSchool.csproj b/exercises/practice/grade-school/GradeSchool.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/grade-school/GradeSchool.csproj
+++ b/exercises/practice/grade-school/GradeSchool.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/grains/Grains.csproj b/exercises/practice/grains/Grains.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/grains/Grains.csproj
+++ b/exercises/practice/grains/Grains.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/grep/Grep.csproj b/exercises/practice/grep/Grep.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/grep/Grep.csproj
+++ b/exercises/practice/grep/Grep.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/hamming/Hamming.csproj b/exercises/practice/hamming/Hamming.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/hamming/Hamming.csproj
+++ b/exercises/practice/hamming/Hamming.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/hangman/Hangman.csproj b/exercises/practice/hangman/Hangman.csproj
index 53f96edf11..95747a0a3c 100644
--- a/exercises/practice/hangman/Hangman.csproj
+++ b/exercises/practice/hangman/Hangman.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/hello-world/HelloWorld.csproj b/exercises/practice/hello-world/HelloWorld.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/hello-world/HelloWorld.csproj
+++ b/exercises/practice/hello-world/HelloWorld.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/hexadecimal/Hexadecimal.csproj b/exercises/practice/hexadecimal/Hexadecimal.csproj
index a5ea09ee4e..01de85b07d 100644
--- a/exercises/practice/hexadecimal/Hexadecimal.csproj
+++ b/exercises/practice/hexadecimal/Hexadecimal.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/high-scores/HighScores.csproj b/exercises/practice/high-scores/HighScores.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/high-scores/HighScores.csproj
+++ b/exercises/practice/high-scores/HighScores.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/house/House.csproj b/exercises/practice/house/House.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/house/House.csproj
+++ b/exercises/practice/house/House.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/isbn-verifier/IsbnVerifier.csproj b/exercises/practice/isbn-verifier/IsbnVerifier.csproj
index 6eb0a8acc2..c7058aecd4 100644
--- a/exercises/practice/isbn-verifier/IsbnVerifier.csproj
+++ b/exercises/practice/isbn-verifier/IsbnVerifier.csproj
@@ -2,7 +2,7 @@
 
   
     Exe
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/isogram/Isogram.csproj b/exercises/practice/isogram/Isogram.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/isogram/Isogram.csproj
+++ b/exercises/practice/isogram/Isogram.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/kindergarten-garden/KindergartenGarden.csproj b/exercises/practice/kindergarten-garden/KindergartenGarden.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/kindergarten-garden/KindergartenGarden.csproj
+++ b/exercises/practice/kindergarten-garden/KindergartenGarden.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/largest-series-product/LargestSeriesProduct.csproj b/exercises/practice/largest-series-product/LargestSeriesProduct.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/largest-series-product/LargestSeriesProduct.csproj
+++ b/exercises/practice/largest-series-product/LargestSeriesProduct.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/leap/Leap.csproj b/exercises/practice/leap/Leap.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/leap/Leap.csproj
+++ b/exercises/practice/leap/Leap.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/ledger/Ledger.csproj b/exercises/practice/ledger/Ledger.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/ledger/Ledger.csproj
+++ b/exercises/practice/ledger/Ledger.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/linked-list/LinkedList.csproj b/exercises/practice/linked-list/LinkedList.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/linked-list/LinkedList.csproj
+++ b/exercises/practice/linked-list/LinkedList.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/list-ops/ListOps.csproj b/exercises/practice/list-ops/ListOps.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/list-ops/ListOps.csproj
+++ b/exercises/practice/list-ops/ListOps.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/luhn/Luhn.csproj b/exercises/practice/luhn/Luhn.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/luhn/Luhn.csproj
+++ b/exercises/practice/luhn/Luhn.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/markdown/Markdown.csproj b/exercises/practice/markdown/Markdown.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/markdown/Markdown.csproj
+++ b/exercises/practice/markdown/Markdown.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/matching-brackets/MatchingBrackets.csproj b/exercises/practice/matching-brackets/MatchingBrackets.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/matching-brackets/MatchingBrackets.csproj
+++ b/exercises/practice/matching-brackets/MatchingBrackets.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/matrix/Matrix.csproj b/exercises/practice/matrix/Matrix.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/matrix/Matrix.csproj
+++ b/exercises/practice/matrix/Matrix.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/meetup/Meetup.csproj b/exercises/practice/meetup/Meetup.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/meetup/Meetup.csproj
+++ b/exercises/practice/meetup/Meetup.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/minesweeper/Minesweeper.csproj b/exercises/practice/minesweeper/Minesweeper.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/minesweeper/Minesweeper.csproj
+++ b/exercises/practice/minesweeper/Minesweeper.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/nth-prime/NthPrime.csproj b/exercises/practice/nth-prime/NthPrime.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/nth-prime/NthPrime.csproj
+++ b/exercises/practice/nth-prime/NthPrime.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/nucleotide-count/NucleotideCount.csproj b/exercises/practice/nucleotide-count/NucleotideCount.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/nucleotide-count/NucleotideCount.csproj
+++ b/exercises/practice/nucleotide-count/NucleotideCount.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/ocr-numbers/OcrNumbers.csproj b/exercises/practice/ocr-numbers/OcrNumbers.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/ocr-numbers/OcrNumbers.csproj
+++ b/exercises/practice/ocr-numbers/OcrNumbers.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/octal/Octal.csproj b/exercises/practice/octal/Octal.csproj
index a5ea09ee4e..01de85b07d 100644
--- a/exercises/practice/octal/Octal.csproj
+++ b/exercises/practice/octal/Octal.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/palindrome-products/PalindromeProducts.csproj b/exercises/practice/palindrome-products/PalindromeProducts.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/palindrome-products/PalindromeProducts.csproj
+++ b/exercises/practice/palindrome-products/PalindromeProducts.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/pangram/Pangram.csproj b/exercises/practice/pangram/Pangram.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/pangram/Pangram.csproj
+++ b/exercises/practice/pangram/Pangram.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj b/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj
+++ b/exercises/practice/parallel-letter-frequency/ParallelLetterFrequency.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/pascals-triangle/PascalsTriangle.csproj b/exercises/practice/pascals-triangle/PascalsTriangle.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/pascals-triangle/PascalsTriangle.csproj
+++ b/exercises/practice/pascals-triangle/PascalsTriangle.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/perfect-numbers/PerfectNumbers.csproj b/exercises/practice/perfect-numbers/PerfectNumbers.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/perfect-numbers/PerfectNumbers.csproj
+++ b/exercises/practice/perfect-numbers/PerfectNumbers.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/phone-number/PhoneNumber.csproj b/exercises/practice/phone-number/PhoneNumber.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/phone-number/PhoneNumber.csproj
+++ b/exercises/practice/phone-number/PhoneNumber.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/pig-latin/PigLatin.csproj b/exercises/practice/pig-latin/PigLatin.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/pig-latin/PigLatin.csproj
+++ b/exercises/practice/pig-latin/PigLatin.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/poker/Poker.csproj b/exercises/practice/poker/Poker.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/poker/Poker.csproj
+++ b/exercises/practice/poker/Poker.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/pov/Pov.csproj b/exercises/practice/pov/Pov.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/pov/Pov.csproj
+++ b/exercises/practice/pov/Pov.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/prime-factors/PrimeFactors.csproj b/exercises/practice/prime-factors/PrimeFactors.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/prime-factors/PrimeFactors.csproj
+++ b/exercises/practice/prime-factors/PrimeFactors.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/protein-translation/ProteinTranslation.csproj b/exercises/practice/protein-translation/ProteinTranslation.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/protein-translation/ProteinTranslation.csproj
+++ b/exercises/practice/protein-translation/ProteinTranslation.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/proverb/Proverb.csproj b/exercises/practice/proverb/Proverb.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/proverb/Proverb.csproj
+++ b/exercises/practice/proverb/Proverb.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj b/exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj
+++ b/exercises/practice/pythagorean-triplet/PythagoreanTriplet.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/queen-attack/QueenAttack.csproj b/exercises/practice/queen-attack/QueenAttack.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/queen-attack/QueenAttack.csproj
+++ b/exercises/practice/queen-attack/QueenAttack.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rail-fence-cipher/RailFenceCipher.csproj b/exercises/practice/rail-fence-cipher/RailFenceCipher.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/rail-fence-cipher/RailFenceCipher.csproj
+++ b/exercises/practice/rail-fence-cipher/RailFenceCipher.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/raindrops/Raindrops.csproj b/exercises/practice/raindrops/Raindrops.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/raindrops/Raindrops.csproj
+++ b/exercises/practice/raindrops/Raindrops.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rational-numbers/RationalNumbers.csproj b/exercises/practice/rational-numbers/RationalNumbers.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/rational-numbers/RationalNumbers.csproj
+++ b/exercises/practice/rational-numbers/RationalNumbers.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/react/React.csproj b/exercises/practice/react/React.csproj
index dc8bdb57ee..c8a98cf6d3 100644
--- a/exercises/practice/react/React.csproj
+++ b/exercises/practice/react/React.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rectangles/Rectangles.csproj b/exercises/practice/rectangles/Rectangles.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/rectangles/Rectangles.csproj
+++ b/exercises/practice/rectangles/Rectangles.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/resistor-color-duo/ResistorColorDuo.csproj b/exercises/practice/resistor-color-duo/ResistorColorDuo.csproj
index e41440b9ba..dbe3535d33 100644
--- a/exercises/practice/resistor-color-duo/ResistorColorDuo.csproj
+++ b/exercises/practice/resistor-color-duo/ResistorColorDuo.csproj
@@ -1,6 +1,6 @@
 
   
-    netcoreapp3.0
+    net5.0
     false
   
   
diff --git a/exercises/practice/resistor-color-trio/ResistorColorTrio.csproj b/exercises/practice/resistor-color-trio/ResistorColorTrio.csproj
index c81ef6cb9d..9265bdd6bf 100644
--- a/exercises/practice/resistor-color-trio/ResistorColorTrio.csproj
+++ b/exercises/practice/resistor-color-trio/ResistorColorTrio.csproj
@@ -1,6 +1,6 @@
 
   
-    netcoreapp3.0
+    net5.0
     false
   
   
diff --git a/exercises/practice/resistor-color/ResistorColor.csproj b/exercises/practice/resistor-color/ResistorColor.csproj
index ce8d60251f..0f09436368 100644
--- a/exercises/practice/resistor-color/ResistorColor.csproj
+++ b/exercises/practice/resistor-color/ResistorColor.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rest-api/RestApi.csproj b/exercises/practice/rest-api/RestApi.csproj
index e24fe6686a..901e6d95c5 100644
--- a/exercises/practice/rest-api/RestApi.csproj
+++ b/exercises/practice/rest-api/RestApi.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/reverse-string/ReverseString.csproj b/exercises/practice/reverse-string/ReverseString.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/reverse-string/ReverseString.csproj
+++ b/exercises/practice/reverse-string/ReverseString.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rna-transcription/RnaTranscription.csproj b/exercises/practice/rna-transcription/RnaTranscription.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/rna-transcription/RnaTranscription.csproj
+++ b/exercises/practice/rna-transcription/RnaTranscription.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/robot-name/RobotName.csproj b/exercises/practice/robot-name/RobotName.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/robot-name/RobotName.csproj
+++ b/exercises/practice/robot-name/RobotName.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/robot-simulator/RobotSimulator.csproj b/exercises/practice/robot-simulator/RobotSimulator.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/robot-simulator/RobotSimulator.csproj
+++ b/exercises/practice/robot-simulator/RobotSimulator.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/roman-numerals/RomanNumerals.csproj b/exercises/practice/roman-numerals/RomanNumerals.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/roman-numerals/RomanNumerals.csproj
+++ b/exercises/practice/roman-numerals/RomanNumerals.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/rotational-cipher/RotationalCipher.csproj b/exercises/practice/rotational-cipher/RotationalCipher.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/rotational-cipher/RotationalCipher.csproj
+++ b/exercises/practice/rotational-cipher/RotationalCipher.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/run-length-encoding/RunLengthEncoding.csproj b/exercises/practice/run-length-encoding/RunLengthEncoding.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/run-length-encoding/RunLengthEncoding.csproj
+++ b/exercises/practice/run-length-encoding/RunLengthEncoding.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/saddle-points/SaddlePoints.csproj b/exercises/practice/saddle-points/SaddlePoints.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/saddle-points/SaddlePoints.csproj
+++ b/exercises/practice/saddle-points/SaddlePoints.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/say/Say.csproj b/exercises/practice/say/Say.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/say/Say.csproj
+++ b/exercises/practice/say/Say.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/scale-generator/ScaleGenerator.csproj b/exercises/practice/scale-generator/ScaleGenerator.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/scale-generator/ScaleGenerator.csproj
+++ b/exercises/practice/scale-generator/ScaleGenerator.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/scrabble-score/ScrabbleScore.csproj b/exercises/practice/scrabble-score/ScrabbleScore.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/scrabble-score/ScrabbleScore.csproj
+++ b/exercises/practice/scrabble-score/ScrabbleScore.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/secret-handshake/SecretHandshake.csproj b/exercises/practice/secret-handshake/SecretHandshake.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/secret-handshake/SecretHandshake.csproj
+++ b/exercises/practice/secret-handshake/SecretHandshake.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/series/Series.csproj b/exercises/practice/series/Series.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/series/Series.csproj
+++ b/exercises/practice/series/Series.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/sgf-parsing/SgfParsing.csproj b/exercises/practice/sgf-parsing/SgfParsing.csproj
index 6b07dda347..d78dc03f62 100644
--- a/exercises/practice/sgf-parsing/SgfParsing.csproj
+++ b/exercises/practice/sgf-parsing/SgfParsing.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/sieve/Sieve.csproj b/exercises/practice/sieve/Sieve.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/sieve/Sieve.csproj
+++ b/exercises/practice/sieve/Sieve.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/simple-cipher/SimpleCipher.csproj b/exercises/practice/simple-cipher/SimpleCipher.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/simple-cipher/SimpleCipher.csproj
+++ b/exercises/practice/simple-cipher/SimpleCipher.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/simple-linked-list/SimpleLinkedList.csproj b/exercises/practice/simple-linked-list/SimpleLinkedList.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/simple-linked-list/SimpleLinkedList.csproj
+++ b/exercises/practice/simple-linked-list/SimpleLinkedList.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/space-age/SpaceAge.csproj b/exercises/practice/space-age/SpaceAge.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/space-age/SpaceAge.csproj
+++ b/exercises/practice/space-age/SpaceAge.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/spiral-matrix/SpiralMatrix.csproj b/exercises/practice/spiral-matrix/SpiralMatrix.csproj
index e24fe6686a..901e6d95c5 100644
--- a/exercises/practice/spiral-matrix/SpiralMatrix.csproj
+++ b/exercises/practice/spiral-matrix/SpiralMatrix.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/strain/Strain.csproj b/exercises/practice/strain/Strain.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/strain/Strain.csproj
+++ b/exercises/practice/strain/Strain.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/sublist/Sublist.csproj b/exercises/practice/sublist/Sublist.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/sublist/Sublist.csproj
+++ b/exercises/practice/sublist/Sublist.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/sum-of-multiples/SumOfMultiples.csproj b/exercises/practice/sum-of-multiples/SumOfMultiples.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/sum-of-multiples/SumOfMultiples.csproj
+++ b/exercises/practice/sum-of-multiples/SumOfMultiples.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/tournament/Tournament.csproj b/exercises/practice/tournament/Tournament.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/tournament/Tournament.csproj
+++ b/exercises/practice/tournament/Tournament.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/transpose/Transpose.csproj b/exercises/practice/transpose/Transpose.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/transpose/Transpose.csproj
+++ b/exercises/practice/transpose/Transpose.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/tree-building/TreeBuilding.csproj b/exercises/practice/tree-building/TreeBuilding.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/tree-building/TreeBuilding.csproj
+++ b/exercises/practice/tree-building/TreeBuilding.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/triangle/Triangle.csproj b/exercises/practice/triangle/Triangle.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/triangle/Triangle.csproj
+++ b/exercises/practice/triangle/Triangle.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/trinary/Trinary.csproj b/exercises/practice/trinary/Trinary.csproj
index a5ea09ee4e..01de85b07d 100644
--- a/exercises/practice/trinary/Trinary.csproj
+++ b/exercises/practice/trinary/Trinary.csproj
@@ -1,7 +1,7 @@
 
 
   
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/twelve-days/TwelveDays.csproj b/exercises/practice/twelve-days/TwelveDays.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/twelve-days/TwelveDays.csproj
+++ b/exercises/practice/twelve-days/TwelveDays.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/two-bucket/TwoBucket.csproj b/exercises/practice/two-bucket/TwoBucket.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/two-bucket/TwoBucket.csproj
+++ b/exercises/practice/two-bucket/TwoBucket.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/two-fer/TwoFer.csproj b/exercises/practice/two-fer/TwoFer.csproj
index e24fe6686a..901e6d95c5 100644
--- a/exercises/practice/two-fer/TwoFer.csproj
+++ b/exercises/practice/two-fer/TwoFer.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj b/exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj
+++ b/exercises/practice/variable-length-quantity/VariableLengthQuantity.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/word-count/WordCount.csproj b/exercises/practice/word-count/WordCount.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/word-count/WordCount.csproj
+++ b/exercises/practice/word-count/WordCount.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/word-search/WordSearch.csproj b/exercises/practice/word-search/WordSearch.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/word-search/WordSearch.csproj
+++ b/exercises/practice/word-search/WordSearch.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/wordy/Wordy.csproj b/exercises/practice/wordy/Wordy.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/wordy/Wordy.csproj
+++ b/exercises/practice/wordy/Wordy.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/yacht/Yacht.csproj b/exercises/practice/yacht/Yacht.csproj
index df9421acd6..6fc8c478c3 100644
--- a/exercises/practice/yacht/Yacht.csproj
+++ b/exercises/practice/yacht/Yacht.csproj
@@ -2,7 +2,7 @@
 
   
     Exe
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/zebra-puzzle/ZebraPuzzle.csproj b/exercises/practice/zebra-puzzle/ZebraPuzzle.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/zebra-puzzle/ZebraPuzzle.csproj
+++ b/exercises/practice/zebra-puzzle/ZebraPuzzle.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/exercises/practice/zipper/Zipper.csproj b/exercises/practice/zipper/Zipper.csproj
index c511cdfaca..13172838ba 100644
--- a/exercises/practice/zipper/Zipper.csproj
+++ b/exercises/practice/zipper/Zipper.csproj
@@ -1,7 +1,7 @@
 
 
       
-    netcoreapp3.0
+    net5.0
   
 
   
diff --git a/generators/Generators.csproj b/generators/Generators.csproj
index d6563f20cd..6eee9f78e9 100644
--- a/generators/Generators.csproj
+++ b/generators/Generators.csproj
@@ -1,7 +1,7 @@
 
   
     Exe
-    netcoreapp3.0
+    net5.0
     Exercism.CSharp
   
   

From b6069be604dad0f58a02ee6eb7217ac20fcf87b7 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 9 Feb 2021 09:26:19 +0100
Subject: [PATCH 325/327] scripts: test practice and concept exercises (#1493)

---
 exercises/Exercises.sln | 1673 +++++++++++++++++++++++++--------------
 test.ps1                |   39 +-
 2 files changed, 1087 insertions(+), 625 deletions(-)

diff --git a/exercises/Exercises.sln b/exercises/Exercises.sln
index f9c1625136..bcbdb73a0b 100644
--- a/exercises/Exercises.sln
+++ b/exercises/Exercises.sln
@@ -1,750 +1,1191 @@
-Microsoft Visual Studio Solution File, Format Version 12.00
+
+Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 15
-VisualStudioVersion = 15.0.26730.12
+VisualStudioVersion = 15.0.26124.0
 MinimumVisualStudioVersion = 15.0.26124.0
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Accumulate", "accumulate\Accumulate.csproj", "{F16C0EE1-6923-4328-B015-363CF24FF867}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "concept", "concept", "{3303F74B-62AC-47B7-A8AA-F93A52A1C95C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Acronym", "acronym\Acronym.csproj", "{0B8FF29D-6707-4112-8398-6F383A31524D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnnalynsInfiltration", "concept\annalyns-infiltration\AnnalynsInfiltration.csproj", "{DBDE9159-2423-4473-9853-4101095D93A2}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AllYourBase", "all-your-base\AllYourBase.csproj", "{CFA7CC8D-C585-4AE6-BAD0-840D3DC62A43}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AttackOfTheTrolls", "concept\attack-of-the-trolls\AttackOfTheTrolls.csproj", "{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Allergies", "allergies\Allergies.csproj", "{C9372234-0F42-4E0E-BD55-EAC351D9256C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AuthenticationSystem", "concept\authentication-system\AuthenticationSystem.csproj", "{758FC429-A223-439E-B4C4-3FC5E318468C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Alphametics", "alphametics\Alphametics.csproj", "{BA7E7612-8AE8-4246-8E09-190445DF9900}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeautySalonGoesGlobal", "concept\beauty-salon-goes-global\BeautySalonGoesGlobal.csproj", "{F185E45E-9806-4617-BF97-635FCEB61680}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Anagram", "anagram\Anagram.csproj", "{815C764D-CC32-4BD9-8F32-78A2D030C71E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BirdWatcher", "concept\bird-watcher\BirdWatcher.csproj", "{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AtbashCipher", "atbash-cipher\AtbashCipher.csproj", "{4CEF0893-7AE3-455E-98C1-89BB822AC1C2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BookingUpForBeauty", "concept\booking-up-for-beauty\BookingUpForBeauty.csproj", "{331F0F1E-6A35-4E22-BBFA-004A1D4EE757}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BankAccount", "bank-account\BankAccount.csproj", "{12BF4BEE-261C-42B8-B2DC-D80262744AC2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildingTelemetry", "concept\building-telemetry\BuildingTelemetry.csproj", "{1B613B04-C002-48F8-B320-EA7BCC8483A7}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BeerSong", "beer-song\BeerSong.csproj", "{BE87F8A4-E216-40A7-86CF-153A15BAFEF8}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CalculatorConundrum", "concept\calculator-conundrum\CalculatorConundrum.csproj", "{BA955D45-C36D-4CDC-A0BA-708432C63B3E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinarySearch", "binary-search\BinarySearch.csproj", "{1F8B6B66-7A58-4F84-9D3A-FB454D2CC3E2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CarsAssemble", "concept\cars-assemble\CarsAssemble.csproj", "{1C829A36-C841-4BD6-993D-1F6EA3998B12}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BinarySearchTree", "binary-search-tree\BinarySearchTree.csproj", "{6FBC562A-7721-4846-81B6-D79D5AF576C5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WhyCantIPushToMain", "concept\developer-privileges\WhyCantIPushToMain.csproj", "{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bob", "bob\Bob.csproj", "{C8D01AEE-9AD9-4134-9721-3442C59702B2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ElonsToys", "concept\elons-toys\ElonsToys.csproj", "{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BookStore", "book-store\BookStore.csproj", "{F9175D9F-7602-4BE1-B565-EA723D0CDF0A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Faceid2", "concept\faceid-2\Faceid2.csproj", "{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bowling", "bowling\Bowling.csproj", "{CE0CA302-A594-422D-A215-E78F2F3AF0CE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FootballMatchReports", "concept\football-match-reports\FootballMatchReports.csproj", "{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MatchingBrackets", "matching-brackets\MatchingBrackets.csproj", "{A9584773-6FD0-42CB-B94E-A61125C5C1E7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HighSchoolSweethearts", "concept\high-school-sweethearts\HighSchoolSweethearts.csproj", "{E55BB790-87EC-4C8E-9908-8D0C01E5C215}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Change", "change\Change.csproj", "{31595C04-4C0E-4A72-90A1-054EE5C47BFC}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyperOptimizedTelemetry", "concept\hyper-optimized-telemetry\HyperOptimizedTelemetry.csproj", "{E3D46015-AB12-47AB-AB37-5FFF5B781BD9}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CircularBuffer", "circular-buffer\CircularBuffer.csproj", "{A3016178-CED9-4DDD-8FF4-03C420AD77B9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyperiaForex", "concept\hyperia-forex\HyperiaForex.csproj", "{62F13963-52BC-4513-B2F5-ED5E07146860}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Clock", "clock\Clock.csproj", "{D498F024-BA85-4543-88F9-1DCF239470C7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HyperinflationHitsHyperia", "concept\hyperinflation-hits-hyperia\HyperinflationHitsHyperia.csproj", "{17A5BDBE-C1D1-452E-8627-CE492B3E56BE}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Connect", "connect\Connect.csproj", "{2C9B22CE-770A-400B-BD9B-287030CF12BB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InstrumentsOfTexas", "concept\instruments-of-texas\InstrumentsOfTexas.csproj", "{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CryptoSquare", "crypto-square\CryptoSquare.csproj", "{A6151CB7-713E-43B0-A403-9C73F9936D4B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InterestIsInteresting", "concept\interest-is-interesting\InterestIsInteresting.csproj", "{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CustomSet", "custom-set\CustomSet.csproj", "{3ED88500-2825-4F24-81E6-C816FF89A5B5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InternationalCallingConnoisseur", "concept\international-calling-connoisseur\InternationalCallingConnoisseur.csproj", "{9557D34F-A76C-4A04-92F6-7769676C60B1}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Diamond", "diamond\Diamond.csproj", "{93092B18-7447-4F06-AD46-FC7B39EC9E89}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LandGrabInSpace", "concept\land-grab-in-space\LandGrabInSpace.csproj", "{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DifferenceOfSquares", "difference-of-squares\DifferenceOfSquares.csproj", "{07DA1459-6101-43E1-A1AF-48ABD8D62ADD}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogLevels", "concept\log-levels\LogLevels.csproj", "{22D6F789-FE96-48DB-ACC1-3A52664B9F9E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiffieHellman", "diffie-hellman\DiffieHellman.csproj", "{58000112-543C-401E-9D1C-EBABC5A67A14}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LogsLogsLogs", "concept\logs-logs-logs\LogsLogsLogs.csproj", "{F72896F4-43E6-4FBC-8D7D-D0306657DE34}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Dominoes", "dominoes\Dominoes.csproj", "{99CCDA48-1CA3-46B9-89B8-0B45106304FC}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LuciansLusciousLasagna", "concept\lucians-luscious-lasagna\LuciansLusciousLasagna.csproj", "{B512C62C-677E-4A07-8B96-E973005501E6}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotDsl", "dot-dsl\DotDsl.csproj", "{45A818E0-8CDF-44A5-B948-63D8DEB9982E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NeedForSpeed", "concept\need-for-speed\NeedForSpeed.csproj", "{3B766FF7-0B73-409C-AC9F-833FA152BD0C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ErrorHandling", "error-handling\ErrorHandling.csproj", "{B341FE12-9233-4E34-8C1C-4E62AC2F8AE1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ObjectRelationalMapping", "concept\object-relational-mapping\ObjectRelationalMapping.csproj", "{FB29A674-B8AC-4A1E-9D64-6DC151E7884E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Etl", "etl\Etl.csproj", "{B7E811DB-8575-4C77-9AF9-49DA840557C2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrmInOneGo", "concept\orm-in-one-go\OrmInOneGo.csproj", "{842EF7A8-F305-42BC-8740-9ABB58202606}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FlattenArray", "flatten-array\FlattenArray.csproj", "{FD52020A-6F1E-42FA-81CE-1F6A8E7C9737}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsingLogFiles", "concept\parsing-log-files\ParsingLogFiles.csproj", "{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FoodChain", "food-chain\FoodChain.csproj", "{FED33EF6-AC47-4E9A-B615-66B16B846E94}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneNumberAnalysis", "concept\phone-number-analysis\PhoneNumberAnalysis.csproj", "{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Forth", "forth\Forth.csproj", "{ACB24C7C-C92D-43F9-B1B1-9444696DAD36}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RedVsBlueDarwinStyle", "concept\red-vs-blue-darwin-style\RedVsBlueDarwinStyle.csproj", "{F67A2623-4C33-46D4-9CE3-827C59240089}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gigasecond", "gigasecond\Gigasecond.csproj", "{2C8C5AE3-D04F-48F4-8AF5-D7535277B7A0}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteControlCleanup", "concept\remote-control-cleanup\RemoteControlCleanup.csproj", "{86830781-83E7-40D4-AC04-9F8CB730C5CF}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GoCounting", "go-counting\GoCounting.csproj", "{A5417213-F20A-4C06-9D8B-8688B0C4EE61}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RemoteControlCompetition", "concept\remote-control-competition\RemoteControlCompetition.csproj", "{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GradeSchool", "grade-school\GradeSchool.csproj", "{A03A743F-C645-45CB-80A0-BE10D2FC1A13}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RollTheDie", "concept\roll-the-die\RollTheDie.csproj", "{42F380C0-9B44-40FD-8F15-19D949CCB2BD}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grains", "grains\Grains.csproj", "{29C6234D-5562-4495-A014-92388EE4518E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecureMunchesterUnited", "concept\secure-munchester-united\SecureMunchesterUnited.csproj", "{85B57E4B-C0CC-45A2-BA93-A10302AC9080}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Grep", "grep\Grep.csproj", "{4427F391-652B-4804-BED4-7CD0D218FE28}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqueakyClean", "concept\squeaky-clean\SqueakyClean.csproj", "{F85A785C-195A-4B88-9563-6AFED7D8A398}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hamming", "hamming\Hamming.csproj", "{61BAD6B6-3A48-4E9B-8333-F1884F68A0A5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheWeatherInDeather", "concept\the-weather-in-deather\TheWeatherInDeather.csproj", "{FC58281F-374A-4C48-B00E-BB46D6EE2B89}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Hangman", "hangman\Hangman.csproj", "{DE23A75D-E816-4988-BB2C-7EBEB5BEB6F1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimFromMarketing", "concept\tim-from-marketing\TimFromMarketing.csproj", "{48E8B6EF-A590-417C-B7B9-A6345FCD70A0}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "HelloWorld", "hello-world\HelloWorld.csproj", "{0CC90F16-9B6C-4C87-A49B-600DB3DF0D2A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TracksOnTracksOnTracks", "concept\tracks-on-tracks-on-tracks\TracksOnTracksOnTracks.csproj", "{D9D540F8-AEAA-4076-A5A5-5711FC451D99}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "House", "house\House.csproj", "{4D68748B-6DEF-4E05-830C-43AF09B2CE8A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WeighingMachine", "concept\weighing-machine\WeighingMachine.csproj", "{7F321163-AD3F-4F08-83B9-714BDA5FE088}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Isogram", "isogram\Isogram.csproj", "{91CF9FC4-105B-4E21-8692-1D5E539E42E9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WizardsAndWarriors", "concept\wizards-and-warriors\WizardsAndWarriors.csproj", "{3329B3ED-C681-4BA4-9947-5F152A38FD0D}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KindergartenGarden", "kindergarten-garden\KindergartenGarden.csproj", "{D504C93E-AE1A-4852-9727-6E565632D38E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WizardsAndWarriors2", "concept\wizards-and-warriors-2\WizardsAndWarriors2.csproj", "{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LargestSeriesProduct", "largest-series-product\LargestSeriesProduct.csproj", "{1632128F-A60B-49B8-A5DB-05F3F1A3B84C}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "practice", "practice", "{E276EF69-669A-43E0-88AC-8ABB17A9C026}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Leap", "leap\Leap.csproj", "{8CA92DF0-3C60-4F23-9890-806744E1F514}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Accumulate", "practice\accumulate\Accumulate.csproj", "{684FA1FC-5BA3-4089-B6C4-5E6797D463C2}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ledger", "ledger\Ledger.csproj", "{507ED1D4-F905-4AAD-897D-AD403FA56663}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Acronym", "practice\acronym\Acronym.csproj", "{863F435B-B7C7-4CC8-9A4F-2267385B8487}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LinkedList", "linked-list\LinkedList.csproj", "{C9ADF8BA-8239-4514-8906-A8E09A1A874C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AffineCipher", "practice\affine-cipher\AffineCipher.csproj", "{FBDEECDC-AF92-42B3-AE69-3AF91F26F683}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ListOps", "list-ops\ListOps.csproj", "{7370EDAC-0F7C-4008-A8C6-8C6240EE518E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AllYourBase", "practice\all-your-base\AllYourBase.csproj", "{BE366E7A-F7C8-4AB2-9928-04FC68238883}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Luhn", "luhn\Luhn.csproj", "{6B934B23-6A75-42FC-9B6C-B3F4CFA6673F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allergies", "practice\allergies\Allergies.csproj", "{A405FB21-249D-4F71-A46E-D943021BA33F}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Markdown", "markdown\Markdown.csproj", "{AFA39C3B-C0A0-445C-8129-4DFD3009B56E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Alphametics", "practice\alphametics\Alphametics.csproj", "{54EBB5D5-B14C-4297-945E-1A3C11B51740}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Matrix", "matrix\Matrix.csproj", "{BCC05EA8-DB49-4684-9888-1B8688BE3FA6}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Anagram", "practice\anagram\Anagram.csproj", "{A6CE175A-285A-40C1-ABA8-90A9E483FB70}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meetup", "meetup\Meetup.csproj", "{87FCABD0-2762-464E-9489-415E95D12427}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArmstrongNumbers", "practice\armstrong-numbers\ArmstrongNumbers.csproj", "{3B0DA602-0415-408E-A3AC-84B3EC23DE13}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Minesweeper", "minesweeper\Minesweeper.csproj", "{C84E079F-9790-425A-9C86-C69122811E6F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AtbashCipher", "practice\atbash-cipher\AtbashCipher.csproj", "{EB3333ED-3B41-4C2A-A979-C224E4B7C646}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NthPrime", "nth-prime\NthPrime.csproj", "{F437861F-4FF8-418E-B205-FB04D23E0312}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BankAccount", "practice\bank-account\BankAccount.csproj", "{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NucleotideCount", "nucleotide-count\NucleotideCount.csproj", "{6A9E4125-03D1-4DAF-8333-336C49360621}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeerSong", "practice\beer-song\BeerSong.csproj", "{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OcrNumbers", "ocr-numbers\OcrNumbers.csproj", "{1BA7884A-3D6F-4479-A0F9-44385662FE24}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Binary", "practice\binary\Binary.csproj", "{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PalindromeProducts", "palindrome-products\PalindromeProducts.csproj", "{FBE7E7D4-EBF1-4B0C-B63E-540DA1C9CEAA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinarySearch", "practice\binary-search\BinarySearch.csproj", "{1FD342FB-67C0-4A93-8DCE-93180CAF38A2}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pangram", "pangram\Pangram.csproj", "{7E047279-FD70-440F-8FB9-B47E88747EF4}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BinarySearchTree", "practice\binary-search-tree\BinarySearchTree.csproj", "{F74F4279-B424-49A9-A539-909FD5298A04}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParallelLetterFrequency", "parallel-letter-frequency\ParallelLetterFrequency.csproj", "{A60E1C9A-6E52-42F7-ACA2-BB58DA64361E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bob", "practice\bob\Bob.csproj", "{5A24CA2C-7E8F-4123-9B2C-9866957A76B9}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PascalsTriangle", "pascals-triangle\PascalsTriangle.csproj", "{427A9EFA-5E06-4176-A287-0DC0E0CD3E86}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BookStore", "practice\book-store\BookStore.csproj", "{B9285667-4EBE-4EF7-AB66-396F8651BDAD}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfectNumbers", "perfect-numbers\PerfectNumbers.csproj", "{4B864ACE-495C-46FB-870F-4D794C02C8F9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bowling", "practice\bowling\Bowling.csproj", "{97E48A24-B5CB-478E-AF2A-B8FB2350DB12}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PhoneNumber", "phone-number\PhoneNumber.csproj", "{17419CBD-2AC6-479F-ACA7-D478F9FBF397}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Change", "practice\change\Change.csproj", "{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PigLatin", "pig-latin\PigLatin.csproj", "{03856292-CE47-45EE-91D4-6ACF27E1925F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CircularBuffer", "practice\circular-buffer\CircularBuffer.csproj", "{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Poker", "poker\Poker.csproj", "{762A1A84-4B1E-49A1-BC58-4988BB489F7C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Clock", "practice\clock\Clock.csproj", "{CB9E0567-82A1-4E03-95B9-8397A80A7144}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Pov", "pov\Pov.csproj", "{3B42D204-BFB1-456F-B5F5-9421EECE465A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CollatzConjecture", "practice\collatz-conjecture\CollatzConjecture.csproj", "{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PrimeFactors", "prime-factors\PrimeFactors.csproj", "{F8BC96E4-15E2-4F64-9D25-E167EC207404}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ComplexNumbers", "practice\complex-numbers\ComplexNumbers.csproj", "{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProteinTranslation", "protein-translation\ProteinTranslation.csproj", "{A2EB7FD7-7660-4297-B431-9833CB65A848}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Connect", "practice\connect\Connect.csproj", "{7628BE7F-AD0D-4C08-95FF-907E78593169}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Proverb", "proverb\Proverb.csproj", "{086D5907-AAF8-4488-A2AD-4A3430D74FAB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CryptoSquare", "practice\crypto-square\CryptoSquare.csproj", "{21C347CC-D097-4B78-8B2D-9763B3FA868E}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PythagoreanTriplet", "pythagorean-triplet\PythagoreanTriplet.csproj", "{6ACF8F5B-B1E1-439B-AFFF-42D6B143760E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CustomSet", "practice\custom-set\CustomSet.csproj", "{78FBF12B-FF17-4FAB-A51C-375DFB376A84}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueenAttack", "queen-attack\QueenAttack.csproj", "{50FB388F-6D68-400C-A919-0414B87466A7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Darts", "practice\darts\Darts.csproj", "{6E91AA59-BD05-49EC-8DEA-C69542C8438F}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RailFenceCipher", "rail-fence-cipher\RailFenceCipher.csproj", "{F1957BE5-4CA4-494B-A62B-AA4F5E4D460A}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Diamond", "practice\diamond\Diamond.csproj", "{A680BF33-6C6E-4093-84C1-813C51BDA1E7}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Raindrops", "raindrops\Raindrops.csproj", "{F2077E7E-7305-4FC7-8D67-D90037B3F370}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DifferenceOfSquares", "practice\difference-of-squares\DifferenceOfSquares.csproj", "{4BC37EC1-225E-4949-AAE0-44E3DCE0E141}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "React", "react\React.csproj", "{3A3D27B8-10FE-4E72-A3CE-183EBC11503B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DiffieHellman", "practice\diffie-hellman\DiffieHellman.csproj", "{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rectangles", "rectangles\Rectangles.csproj", "{A8777E05-E344-4673-915B-E9224002C423}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DndCharacter", "practice\dnd-character\DndCharacter.csproj", "{C43D0602-7C1C-46BA-B4C4-FBC1C1428859}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RnaTranscription", "rna-transcription\RnaTranscription.csproj", "{05B08A0C-5BCA-4FF6-9C42-9DFF5E7DCDEA}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dominoes", "practice\dominoes\Dominoes.csproj", "{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RobotName", "robot-name\RobotName.csproj", "{C9CFE66E-6921-4CCE-83A7-D5B54812122F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotDsl", "practice\dot-dsl\DotDsl.csproj", "{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RobotSimulator", "robot-simulator\RobotSimulator.csproj", "{A0FD4472-99E5-4FBC-A6A7-20786EA167DF}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ErrorHandling", "practice\error-handling\ErrorHandling.csproj", "{53713CF1-576B-480A-B40A-1753A4A90CC3}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RomanNumerals", "roman-numerals\RomanNumerals.csproj", "{86272012-C994-41F7-BFAF-4BED50797B22}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Etl", "practice\etl\Etl.csproj", "{EF104B33-8F43-458A-9533-597CF8389004}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RunLengthEncoding", "run-length-encoding\RunLengthEncoding.csproj", "{94B89563-1E74-42F9-96A5-19CD800AFECB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlattenArray", "practice\flatten-array\FlattenArray.csproj", "{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SaddlePoints", "saddle-points\SaddlePoints.csproj", "{E5D2964E-CFE9-4DE6-99B5-1F54F9984F65}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FoodChain", "practice\food-chain\FoodChain.csproj", "{802FAF1C-3A5E-44D9-8D0A-ED292579CF00}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Say", "say\Say.csproj", "{C92F8E81-6FB1-46FF-9B68-2D126F8903E6}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Forth", "practice\forth\Forth.csproj", "{E582C914-C7B0-4812-92DE-7849F485EAD4}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScaleGenerator", "scale-generator\ScaleGenerator.csproj", "{B9207BE6-2577-4C49-AF5F-130A17BBEA73}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Gigasecond", "practice\gigasecond\Gigasecond.csproj", "{FFE3F9EB-D6F9-47EE-AA5F-486053610D80}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScrabbleScore", "scrabble-score\ScrabbleScore.csproj", "{40C19FFA-E1E1-4589-86E4-B7BEF336CE79}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GoCounting", "practice\go-counting\GoCounting.csproj", "{A901A7DB-5CAC-4245-9920-6BC28DCC94D8}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SecretHandshake", "secret-handshake\SecretHandshake.csproj", "{64324C38-03F7-4624-8F00-B85183DDBF99}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GradeSchool", "practice\grade-school\GradeSchool.csproj", "{0DA78D58-5ABC-4C33-B390-A3022E815B36}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Series", "series\Series.csproj", "{14C24193-D5E0-4D29-B270-C27B43CC1925}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grains", "practice\grains\Grains.csproj", "{89D0A49C-D534-4DE0-8357-75F8AE363994}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SgfParsing", "sgf-parsing\SgfParsing.csproj", "{B25208A4-3C80-411E-A36A-7BC4AA506DC7}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Grep", "practice\grep\Grep.csproj", "{A340652C-93D8-42AB-8724-08A0BC737A05}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sieve", "sieve\Sieve.csproj", "{2A56B16C-3980-4380-84E8-B20DEEEFB5D6}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hamming", "practice\hamming\Hamming.csproj", "{58B4C338-F610-4227-8685-DD04393587A0}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleCipher", "simple-cipher\SimpleCipher.csproj", "{269971FF-B748-4B95-8507-534C229A60B9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hangman", "practice\hangman\Hangman.csproj", "{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleLinkedList", "simple-linked-list\SimpleLinkedList.csproj", "{F6244150-1AD9-470E-B0F0-72389B10639E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HelloWorld", "practice\hello-world\HelloWorld.csproj", "{672CEA36-D471-4ECA-9FB4-CE4576835A28}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpaceAge", "space-age\SpaceAge.csproj", "{D1102F23-265A-4CA8-975C-75564DFFAA04}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hexadecimal", "practice\hexadecimal\Hexadecimal.csproj", "{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Strain", "strain\Strain.csproj", "{F4C5ECB6-2C17-4BC9-BF8F-BA9117BD2843}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HighScores", "practice\high-scores\HighScores.csproj", "{37A064B1-AB4D-4137-B912-B6D358407A26}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sublist", "sublist\Sublist.csproj", "{B9C4BF5F-2D56-4B06-A1EE-1E1CC642D14B}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "House", "practice\house\House.csproj", "{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SumOfMultiples", "sum-of-multiples\SumOfMultiples.csproj", "{6CE987BF-9677-476C-8BB9-1BE7CC16F932}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IsbnVerifier", "practice\isbn-verifier\IsbnVerifier.csproj", "{D0D3DDF6-5338-4751-BA6E-8D64A77201B9}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tournament", "tournament\Tournament.csproj", "{BD63E691-0A53-46CE-B687-E3CD95F1D4B1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Isogram", "practice\isogram\Isogram.csproj", "{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Transpose", "transpose\Transpose.csproj", "{FCF9AB0E-4310-4BCB-8682-833450658B97}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KindergartenGarden", "practice\kindergarten-garden\KindergartenGarden.csproj", "{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TreeBuilding", "tree-building\TreeBuilding.csproj", "{607AB17F-1305-4002-A980-DB60699688F1}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LargestSeriesProduct", "practice\largest-series-product\LargestSeriesProduct.csproj", "{23101060-4031-4158-92F2-0E4995C24ADE}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Triangle", "triangle\Triangle.csproj", "{128B3A5D-E28C-4C7F-8B16-3202D0F73A00}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Leap", "practice\leap\Leap.csproj", "{9D5AF8C8-791B-47F1-986D-27900531B594}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwelveDays", "twelve-days\TwelveDays.csproj", "{B98F63AB-F0C8-4594-98BD-0BBBAEA4C4E9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ledger", "practice\ledger\Ledger.csproj", "{EE8DC120-142D-40EE-A846-2BB56BEA4608}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoBucket", "two-bucket\TwoBucket.csproj", "{62EBA4E5-BD13-4F7C-85E6-65D633B3FB6C}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LinkedList", "practice\linked-list\LinkedList.csproj", "{6F459E05-765F-4DBA-82E3-EAD6A4B2874C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VariableLengthQuantity", "variable-length-quantity\VariableLengthQuantity.csproj", "{DFE95B37-24F5-417A-8C3F-788255CE8A04}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ListOps", "practice\list-ops\ListOps.csproj", "{D06A3406-D4CF-4317-BEB6-A631CB3F51DC}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WordCount", "word-count\WordCount.csproj", "{77E253C3-5FCE-45A4-B285-BE24945E0D70}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Luhn", "practice\luhn\Luhn.csproj", "{B037C0BA-CE27-4C1D-A869-65FF4C4A5689}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WordSearch", "word-search\WordSearch.csproj", "{32ECF281-6D99-42D4-AD00-C8B56A8270F8}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Markdown", "practice\markdown\Markdown.csproj", "{CB025E4C-ED1D-4760-8062-CFEA989914FA}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wordy", "wordy\Wordy.csproj", "{2EBD1C45-9D80-413A-9BE8-4ECB43C06843}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MatchingBrackets", "practice\matching-brackets\MatchingBrackets.csproj", "{65EB1B23-8CFB-445A-A9A4-C139B09F372F}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZebraPuzzle", "zebra-puzzle\ZebraPuzzle.csproj", "{79198D56-C3F2-49D6-B8BF-5BB674B6F7A2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Matrix", "practice\matrix\Matrix.csproj", "{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Zipper", "zipper\Zipper.csproj", "{83504141-FF2A-427E-8A51-9FA0E9037A78}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meetup", "practice\meetup\Meetup.csproj", "{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RotationalCipher", "rotational-cipher\RotationalCipher.csproj", "{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Minesweeper", "practice\minesweeper\Minesweeper.csproj", "{3394C204-52AE-4E13-AB87-8BEDC75CEDD0}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoFer", "two-fer\TwoFer.csproj", "{4B862F51-054D-467F-971D-8A7B72F5B498}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NthPrime", "practice\nth-prime\NthPrime.csproj", "{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SpiralMatrix", "spiral-matrix\SpiralMatrix.csproj", "{05EF2C70-B5B0-4351-B940-041A03A6BB84}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NucleotideCount", "practice\nucleotide-count\NucleotideCount.csproj", "{84182669-486C-43A1-B05B-7BB0CCBC4E6C}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CollatzConjecture", "collatz-conjecture\CollatzConjecture.csproj", "{18BC2EE7-E798-40DE-A346-0B803137E67D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OcrNumbers", "practice\ocr-numbers\OcrNumbers.csproj", "{F264C02C-30E7-49B8-9E86-5B2969243109}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ComplexNumbers", "complex-numbers\ComplexNumbers.csproj", "{D0399EAC-5563-4234-9828-0C607BAF7623}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Octal", "practice\octal\Octal.csproj", "{3ABC8F86-F0E0-4237-91C3-1F268D266701}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IsbnVerifier", "isbn-verifier\IsbnVerifier.csproj", "{72432190-8D4D-4E64-B622-F83BE80A3CBB}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PalindromeProducts", "practice\palindrome-products\PalindromeProducts.csproj", "{5A19A062-FACD-423D-9D83-A48A836F2568}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ReverseString", "reverse-string\ReverseString.csproj", "{D2105979-EE3B-432B-8016-172BA949DE2F}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pangram", "practice\pangram\Pangram.csproj", "{D04B70F8-E958-42D2-A3F5-B6E359CD1990}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ArmstrongNumbers", "armstrong-numbers\ArmstrongNumbers.csproj", "{7015C2C4-4050-4631-9394-7EAF19AB0191}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParallelLetterFrequency", "practice\parallel-letter-frequency\ParallelLetterFrequency.csproj", "{B8327FD5-E268-4A6E-9092-CE57E4966F08}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Yacht", "yacht\Yacht.csproj", "{C029D4C6-3A10-459E-96D7-3E77170A5A10}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PascalsTriangle", "practice\pascals-triangle\PascalsTriangle.csproj", "{5A32459A-FE82-44D6-BE6C-98421FADBBEF}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RationalNumbers", "rational-numbers\RationalNumbers.csproj", "{0CBB430D-BF64-436F-93BE-8E8088DBCBFE}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PerfectNumbers", "practice\perfect-numbers\PerfectNumbers.csproj", "{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AffineCipher", "affine-cipher\AffineCipher.csproj", "{758DDF02-FFE7-4A4A-BD7C-0B189F3257C9}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PhoneNumber", "practice\phone-number\PhoneNumber.csproj", "{98A5AA60-E695-449D-A468-9835F3476A98}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RestApi", "rest-api\RestApi.csproj", "{DFF04F1E-2963-4A88-AF92-D14AD48617F2}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PigLatin", "practice\pig-latin\PigLatin.csproj", "{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97}"
 EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Darts", "darts\Darts.csproj", "{202E2755-AB2F-4EA5-94D0-574487079CFF}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Poker", "practice\poker\Poker.csproj", "{3309FA13-B45B-4A31-B517-C9B54F9B5D5F}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HighScores", "high-scores\HighScores.csproj", "{B287CA86-D25C-40B0-98B9-855064F99EE3}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pov", "practice\pov\Pov.csproj", "{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DndCharacter", "dnd-character\DndCharacter.csproj", "{91499710-DC6A-4494-9661-9D374829E975}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PrimeFactors", "practice\prime-factors\PrimeFactors.csproj", "{9A1B9520-6C5E-4096-9C12-EBA26130DB6F}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColor", "resistor-color\ResistorColor.csproj", "{3E499D5B-C5A9-4BCD-BF35-46D590EC06AD}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProteinTranslation", "practice\protein-translation\ProteinTranslation.csproj", "{882F9ADC-1317-4DFD-82E6-20DD9E596D6A}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColorDuo", "resistor-color-duo\ResistorColorDuo.csproj", "{F16F1FD4-2B74-4E90-83D1-0614843FDF62}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Proverb", "practice\proverb\Proverb.csproj", "{AE9614E9-C32D-4D55-A956-E8B965938AFE}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColorTrio", "resistor-color-trio\ResistorColorTrio.csproj", "{667D7B20-F14D-4129-9BBD-F9F5A0D66A9E}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PythagoreanTriplet", "practice\pythagorean-triplet\PythagoreanTriplet.csproj", "{FF144E37-C3F7-4568-8C8C-BE63EDC78358}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QueenAttack", "practice\queen-attack\QueenAttack.csproj", "{8C4EDF99-9492-4768-B8F5-B3915D876DF9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RailFenceCipher", "practice\rail-fence-cipher\RailFenceCipher.csproj", "{7B18CDC9-66AD-469A-B847-1B38C57F4647}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Raindrops", "practice\raindrops\Raindrops.csproj", "{CBF8AC86-406C-49E5-9261-1A73EACDFF70}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RationalNumbers", "practice\rational-numbers\RationalNumbers.csproj", "{241A462E-9EF2-4AC4-8079-8BF71FE851A4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "React", "practice\react\React.csproj", "{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Rectangles", "practice\rectangles\Rectangles.csproj", "{A3E05FEF-78DE-4016-A74E-094EB696B616}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColor", "practice\resistor-color\ResistorColor.csproj", "{C0501987-3A00-463B-B49E-3AC708B6C4D7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColorDuo", "practice\resistor-color-duo\ResistorColorDuo.csproj", "{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ResistorColorTrio", "practice\resistor-color-trio\ResistorColorTrio.csproj", "{DB17651A-D7F7-4792-B9A8-90D178CCCAE8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RestApi", "practice\rest-api\RestApi.csproj", "{6DFB6C23-0F88-41BA-91D3-61DEDF59359F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReverseString", "practice\reverse-string\ReverseString.csproj", "{4016FAEC-445B-421E-B968-B5FD16A23561}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RnaTranscription", "practice\rna-transcription\RnaTranscription.csproj", "{AD6BD65C-78F1-491A-86ED-820C948E6A1D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobotName", "practice\robot-name\RobotName.csproj", "{DA3D0490-0B26-4722-86A6-F2659E82021E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RobotSimulator", "practice\robot-simulator\RobotSimulator.csproj", "{E9C89268-E9B1-4C5C-87C8-E5645E958040}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RomanNumerals", "practice\roman-numerals\RomanNumerals.csproj", "{FB091C23-709B-4D45-87EC-88AED35A4C46}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RotationalCipher", "practice\rotational-cipher\RotationalCipher.csproj", "{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RunLengthEncoding", "practice\run-length-encoding\RunLengthEncoding.csproj", "{4A5926C5-F481-4167-A380-59F1A97535E3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SaddlePoints", "practice\saddle-points\SaddlePoints.csproj", "{49BF7A70-7280-421A-B6FC-627A967EAEDD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Say", "practice\say\Say.csproj", "{95F44A22-1044-4466-A2CF-F1240F57B3F7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScaleGenerator", "practice\scale-generator\ScaleGenerator.csproj", "{321F9E9B-8819-4125-BC09-B01B3443BE7A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ScrabbleScore", "practice\scrabble-score\ScrabbleScore.csproj", "{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SecretHandshake", "practice\secret-handshake\SecretHandshake.csproj", "{77B57863-479B-4D86-A579-26C865FC0FE0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Series", "practice\series\Series.csproj", "{8767C756-B325-46FF-B071-8F7DEFF08094}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SgfParsing", "practice\sgf-parsing\SgfParsing.csproj", "{5F349082-1993-4BEB-A1D3-473B96776DC5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sieve", "practice\sieve\Sieve.csproj", "{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleCipher", "practice\simple-cipher\SimpleCipher.csproj", "{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLinkedList", "practice\simple-linked-list\SimpleLinkedList.csproj", "{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpaceAge", "practice\space-age\SpaceAge.csproj", "{06820024-0B20-402C-BF9C-EFEC04325C98}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SpiralMatrix", "practice\spiral-matrix\SpiralMatrix.csproj", "{9B09E998-546C-47A3-9ED9-67309AE32945}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Strain", "practice\strain\Strain.csproj", "{DF2DAE3E-E816-48B9-B485-AB023A79622B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sublist", "practice\sublist\Sublist.csproj", "{BEEC53E9-6E35-42B7-893A-425A1A9034FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SumOfMultiples", "practice\sum-of-multiples\SumOfMultiples.csproj", "{B99E8C6E-2058-4103-B4FA-44FF4003D0EA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tournament", "practice\tournament\Tournament.csproj", "{97FB9236-C06B-4000-BAB6-5BC649AA3F3D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Transpose", "practice\transpose\Transpose.csproj", "{D49117D4-43C3-49FF-8DAB-4446543233F4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TreeBuilding", "practice\tree-building\TreeBuilding.csproj", "{63298041-B1A6-4F17-BC1B-F1182BC3D544}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Triangle", "practice\triangle\Triangle.csproj", "{884100F6-FF7A-4317-85D9-DE99569422BF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Trinary", "practice\trinary\Trinary.csproj", "{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwelveDays", "practice\twelve-days\TwelveDays.csproj", "{3AC218EB-EFD5-42B3-9828-38E46307170A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwoBucket", "practice\two-bucket\TwoBucket.csproj", "{E336ACFA-EAB1-475B-AD47-1CD6655D43A3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TwoFer", "practice\two-fer\TwoFer.csproj", "{91E9585D-0547-4246-952E-4E7592510655}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VariableLengthQuantity", "practice\variable-length-quantity\VariableLengthQuantity.csproj", "{CE8948EE-C87D-46AD-B643-30C5CA86F107}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WordCount", "practice\word-count\WordCount.csproj", "{8D0CA149-75ED-4BC0-9AF4-784367BC063B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WordSearch", "practice\word-search\WordSearch.csproj", "{1AB54B73-21AF-412F-B5C5-076C39D0C901}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wordy", "practice\wordy\Wordy.csproj", "{CDCA2085-1915-4AF1-853A-E1B8A88CAABA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yacht", "practice\yacht\Yacht.csproj", "{41C422F6-49CA-4EC5-86CB-78D6720FC822}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZebraPuzzle", "practice\zebra-puzzle\ZebraPuzzle.csproj", "{FCB566EA-EDF0-4D97-8436-C101F384EB76}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Zipper", "practice\zipper\Zipper.csproj", "{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
 		Release|Any CPU = Release|Any CPU
 	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{F16C0EE1-6923-4328-B015-363CF24FF867}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F16C0EE1-6923-4328-B015-363CF24FF867}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F16C0EE1-6923-4328-B015-363CF24FF867}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F16C0EE1-6923-4328-B015-363CF24FF867}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0B8FF29D-6707-4112-8398-6F383A31524D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0B8FF29D-6707-4112-8398-6F383A31524D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0B8FF29D-6707-4112-8398-6F383A31524D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0B8FF29D-6707-4112-8398-6F383A31524D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CFA7CC8D-C585-4AE6-BAD0-840D3DC62A43}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CFA7CC8D-C585-4AE6-BAD0-840D3DC62A43}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CFA7CC8D-C585-4AE6-BAD0-840D3DC62A43}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CFA7CC8D-C585-4AE6-BAD0-840D3DC62A43}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C9372234-0F42-4E0E-BD55-EAC351D9256C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C9372234-0F42-4E0E-BD55-EAC351D9256C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C9372234-0F42-4E0E-BD55-EAC351D9256C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C9372234-0F42-4E0E-BD55-EAC351D9256C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BA7E7612-8AE8-4246-8E09-190445DF9900}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BA7E7612-8AE8-4246-8E09-190445DF9900}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BA7E7612-8AE8-4246-8E09-190445DF9900}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BA7E7612-8AE8-4246-8E09-190445DF9900}.Release|Any CPU.Build.0 = Release|Any CPU
-		{815C764D-CC32-4BD9-8F32-78A2D030C71E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{815C764D-CC32-4BD9-8F32-78A2D030C71E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{815C764D-CC32-4BD9-8F32-78A2D030C71E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{815C764D-CC32-4BD9-8F32-78A2D030C71E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4CEF0893-7AE3-455E-98C1-89BB822AC1C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4CEF0893-7AE3-455E-98C1-89BB822AC1C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4CEF0893-7AE3-455E-98C1-89BB822AC1C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4CEF0893-7AE3-455E-98C1-89BB822AC1C2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{12BF4BEE-261C-42B8-B2DC-D80262744AC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{12BF4BEE-261C-42B8-B2DC-D80262744AC2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{12BF4BEE-261C-42B8-B2DC-D80262744AC2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{12BF4BEE-261C-42B8-B2DC-D80262744AC2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BE87F8A4-E216-40A7-86CF-153A15BAFEF8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BE87F8A4-E216-40A7-86CF-153A15BAFEF8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BE87F8A4-E216-40A7-86CF-153A15BAFEF8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BE87F8A4-E216-40A7-86CF-153A15BAFEF8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{1F8B6B66-7A58-4F84-9D3A-FB454D2CC3E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{1F8B6B66-7A58-4F84-9D3A-FB454D2CC3E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{1F8B6B66-7A58-4F84-9D3A-FB454D2CC3E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{1F8B6B66-7A58-4F84-9D3A-FB454D2CC3E2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6FBC562A-7721-4846-81B6-D79D5AF576C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6FBC562A-7721-4846-81B6-D79D5AF576C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6FBC562A-7721-4846-81B6-D79D5AF576C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6FBC562A-7721-4846-81B6-D79D5AF576C5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C8D01AEE-9AD9-4134-9721-3442C59702B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C8D01AEE-9AD9-4134-9721-3442C59702B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C8D01AEE-9AD9-4134-9721-3442C59702B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C8D01AEE-9AD9-4134-9721-3442C59702B2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F9175D9F-7602-4BE1-B565-EA723D0CDF0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F9175D9F-7602-4BE1-B565-EA723D0CDF0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F9175D9F-7602-4BE1-B565-EA723D0CDF0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F9175D9F-7602-4BE1-B565-EA723D0CDF0A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{CE0CA302-A594-422D-A215-E78F2F3AF0CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{CE0CA302-A594-422D-A215-E78F2F3AF0CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{CE0CA302-A594-422D-A215-E78F2F3AF0CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{CE0CA302-A594-422D-A215-E78F2F3AF0CE}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A9584773-6FD0-42CB-B94E-A61125C5C1E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A9584773-6FD0-42CB-B94E-A61125C5C1E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A9584773-6FD0-42CB-B94E-A61125C5C1E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A9584773-6FD0-42CB-B94E-A61125C5C1E7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{31595C04-4C0E-4A72-90A1-054EE5C47BFC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{31595C04-4C0E-4A72-90A1-054EE5C47BFC}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{31595C04-4C0E-4A72-90A1-054EE5C47BFC}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{31595C04-4C0E-4A72-90A1-054EE5C47BFC}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A3016178-CED9-4DDD-8FF4-03C420AD77B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A3016178-CED9-4DDD-8FF4-03C420AD77B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A3016178-CED9-4DDD-8FF4-03C420AD77B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A3016178-CED9-4DDD-8FF4-03C420AD77B9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D498F024-BA85-4543-88F9-1DCF239470C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D498F024-BA85-4543-88F9-1DCF239470C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D498F024-BA85-4543-88F9-1DCF239470C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D498F024-BA85-4543-88F9-1DCF239470C7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2C9B22CE-770A-400B-BD9B-287030CF12BB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2C9B22CE-770A-400B-BD9B-287030CF12BB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2C9B22CE-770A-400B-BD9B-287030CF12BB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2C9B22CE-770A-400B-BD9B-287030CF12BB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A6151CB7-713E-43B0-A403-9C73F9936D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A6151CB7-713E-43B0-A403-9C73F9936D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A6151CB7-713E-43B0-A403-9C73F9936D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A6151CB7-713E-43B0-A403-9C73F9936D4B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3ED88500-2825-4F24-81E6-C816FF89A5B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3ED88500-2825-4F24-81E6-C816FF89A5B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3ED88500-2825-4F24-81E6-C816FF89A5B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3ED88500-2825-4F24-81E6-C816FF89A5B5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{93092B18-7447-4F06-AD46-FC7B39EC9E89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{93092B18-7447-4F06-AD46-FC7B39EC9E89}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{93092B18-7447-4F06-AD46-FC7B39EC9E89}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{93092B18-7447-4F06-AD46-FC7B39EC9E89}.Release|Any CPU.Build.0 = Release|Any CPU
-		{07DA1459-6101-43E1-A1AF-48ABD8D62ADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{07DA1459-6101-43E1-A1AF-48ABD8D62ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{07DA1459-6101-43E1-A1AF-48ABD8D62ADD}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{07DA1459-6101-43E1-A1AF-48ABD8D62ADD}.Release|Any CPU.Build.0 = Release|Any CPU
-		{58000112-543C-401E-9D1C-EBABC5A67A14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{58000112-543C-401E-9D1C-EBABC5A67A14}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{58000112-543C-401E-9D1C-EBABC5A67A14}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{58000112-543C-401E-9D1C-EBABC5A67A14}.Release|Any CPU.Build.0 = Release|Any CPU
-		{99CCDA48-1CA3-46B9-89B8-0B45106304FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{99CCDA48-1CA3-46B9-89B8-0B45106304FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{99CCDA48-1CA3-46B9-89B8-0B45106304FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{99CCDA48-1CA3-46B9-89B8-0B45106304FC}.Release|Any CPU.Build.0 = Release|Any CPU
-		{45A818E0-8CDF-44A5-B948-63D8DEB9982E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{45A818E0-8CDF-44A5-B948-63D8DEB9982E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{45A818E0-8CDF-44A5-B948-63D8DEB9982E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{45A818E0-8CDF-44A5-B948-63D8DEB9982E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B341FE12-9233-4E34-8C1C-4E62AC2F8AE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B341FE12-9233-4E34-8C1C-4E62AC2F8AE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B341FE12-9233-4E34-8C1C-4E62AC2F8AE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B341FE12-9233-4E34-8C1C-4E62AC2F8AE1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B7E811DB-8575-4C77-9AF9-49DA840557C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B7E811DB-8575-4C77-9AF9-49DA840557C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B7E811DB-8575-4C77-9AF9-49DA840557C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B7E811DB-8575-4C77-9AF9-49DA840557C2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FD52020A-6F1E-42FA-81CE-1F6A8E7C9737}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FD52020A-6F1E-42FA-81CE-1F6A8E7C9737}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FD52020A-6F1E-42FA-81CE-1F6A8E7C9737}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FD52020A-6F1E-42FA-81CE-1F6A8E7C9737}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FED33EF6-AC47-4E9A-B615-66B16B846E94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FED33EF6-AC47-4E9A-B615-66B16B846E94}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FED33EF6-AC47-4E9A-B615-66B16B846E94}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FED33EF6-AC47-4E9A-B615-66B16B846E94}.Release|Any CPU.Build.0 = Release|Any CPU
-		{ACB24C7C-C92D-43F9-B1B1-9444696DAD36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{ACB24C7C-C92D-43F9-B1B1-9444696DAD36}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{ACB24C7C-C92D-43F9-B1B1-9444696DAD36}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{ACB24C7C-C92D-43F9-B1B1-9444696DAD36}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2C8C5AE3-D04F-48F4-8AF5-D7535277B7A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2C8C5AE3-D04F-48F4-8AF5-D7535277B7A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2C8C5AE3-D04F-48F4-8AF5-D7535277B7A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2C8C5AE3-D04F-48F4-8AF5-D7535277B7A0}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A5417213-F20A-4C06-9D8B-8688B0C4EE61}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A5417213-F20A-4C06-9D8B-8688B0C4EE61}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A5417213-F20A-4C06-9D8B-8688B0C4EE61}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A5417213-F20A-4C06-9D8B-8688B0C4EE61}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A03A743F-C645-45CB-80A0-BE10D2FC1A13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A03A743F-C645-45CB-80A0-BE10D2FC1A13}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A03A743F-C645-45CB-80A0-BE10D2FC1A13}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A03A743F-C645-45CB-80A0-BE10D2FC1A13}.Release|Any CPU.Build.0 = Release|Any CPU
-		{29C6234D-5562-4495-A014-92388EE4518E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{29C6234D-5562-4495-A014-92388EE4518E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{29C6234D-5562-4495-A014-92388EE4518E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{29C6234D-5562-4495-A014-92388EE4518E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4427F391-652B-4804-BED4-7CD0D218FE28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4427F391-652B-4804-BED4-7CD0D218FE28}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4427F391-652B-4804-BED4-7CD0D218FE28}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4427F391-652B-4804-BED4-7CD0D218FE28}.Release|Any CPU.Build.0 = Release|Any CPU
-		{61BAD6B6-3A48-4E9B-8333-F1884F68A0A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{61BAD6B6-3A48-4E9B-8333-F1884F68A0A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{61BAD6B6-3A48-4E9B-8333-F1884F68A0A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{61BAD6B6-3A48-4E9B-8333-F1884F68A0A5}.Release|Any CPU.Build.0 = Release|Any CPU
-		{DE23A75D-E816-4988-BB2C-7EBEB5BEB6F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{DE23A75D-E816-4988-BB2C-7EBEB5BEB6F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{DE23A75D-E816-4988-BB2C-7EBEB5BEB6F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{DE23A75D-E816-4988-BB2C-7EBEB5BEB6F1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0CC90F16-9B6C-4C87-A49B-600DB3DF0D2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0CC90F16-9B6C-4C87-A49B-600DB3DF0D2A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0CC90F16-9B6C-4C87-A49B-600DB3DF0D2A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0CC90F16-9B6C-4C87-A49B-600DB3DF0D2A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4D68748B-6DEF-4E05-830C-43AF09B2CE8A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4D68748B-6DEF-4E05-830C-43AF09B2CE8A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4D68748B-6DEF-4E05-830C-43AF09B2CE8A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4D68748B-6DEF-4E05-830C-43AF09B2CE8A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{91CF9FC4-105B-4E21-8692-1D5E539E42E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{91CF9FC4-105B-4E21-8692-1D5E539E42E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{91CF9FC4-105B-4E21-8692-1D5E539E42E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{91CF9FC4-105B-4E21-8692-1D5E539E42E9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D504C93E-AE1A-4852-9727-6E565632D38E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D504C93E-AE1A-4852-9727-6E565632D38E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D504C93E-AE1A-4852-9727-6E565632D38E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D504C93E-AE1A-4852-9727-6E565632D38E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{1632128F-A60B-49B8-A5DB-05F3F1A3B84C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{1632128F-A60B-49B8-A5DB-05F3F1A3B84C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{1632128F-A60B-49B8-A5DB-05F3F1A3B84C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{1632128F-A60B-49B8-A5DB-05F3F1A3B84C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{8CA92DF0-3C60-4F23-9890-806744E1F514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{8CA92DF0-3C60-4F23-9890-806744E1F514}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{8CA92DF0-3C60-4F23-9890-806744E1F514}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{8CA92DF0-3C60-4F23-9890-806744E1F514}.Release|Any CPU.Build.0 = Release|Any CPU
-		{507ED1D4-F905-4AAD-897D-AD403FA56663}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{507ED1D4-F905-4AAD-897D-AD403FA56663}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{507ED1D4-F905-4AAD-897D-AD403FA56663}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{507ED1D4-F905-4AAD-897D-AD403FA56663}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C9ADF8BA-8239-4514-8906-A8E09A1A874C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C9ADF8BA-8239-4514-8906-A8E09A1A874C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C9ADF8BA-8239-4514-8906-A8E09A1A874C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C9ADF8BA-8239-4514-8906-A8E09A1A874C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7370EDAC-0F7C-4008-A8C6-8C6240EE518E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7370EDAC-0F7C-4008-A8C6-8C6240EE518E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7370EDAC-0F7C-4008-A8C6-8C6240EE518E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7370EDAC-0F7C-4008-A8C6-8C6240EE518E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6B934B23-6A75-42FC-9B6C-B3F4CFA6673F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6B934B23-6A75-42FC-9B6C-B3F4CFA6673F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6B934B23-6A75-42FC-9B6C-B3F4CFA6673F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6B934B23-6A75-42FC-9B6C-B3F4CFA6673F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{AFA39C3B-C0A0-445C-8129-4DFD3009B56E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{AFA39C3B-C0A0-445C-8129-4DFD3009B56E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{AFA39C3B-C0A0-445C-8129-4DFD3009B56E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{AFA39C3B-C0A0-445C-8129-4DFD3009B56E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BCC05EA8-DB49-4684-9888-1B8688BE3FA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BCC05EA8-DB49-4684-9888-1B8688BE3FA6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BCC05EA8-DB49-4684-9888-1B8688BE3FA6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BCC05EA8-DB49-4684-9888-1B8688BE3FA6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{87FCABD0-2762-464E-9489-415E95D12427}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{87FCABD0-2762-464E-9489-415E95D12427}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{87FCABD0-2762-464E-9489-415E95D12427}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{87FCABD0-2762-464E-9489-415E95D12427}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C84E079F-9790-425A-9C86-C69122811E6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C84E079F-9790-425A-9C86-C69122811E6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C84E079F-9790-425A-9C86-C69122811E6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C84E079F-9790-425A-9C86-C69122811E6F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F437861F-4FF8-418E-B205-FB04D23E0312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F437861F-4FF8-418E-B205-FB04D23E0312}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F437861F-4FF8-418E-B205-FB04D23E0312}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F437861F-4FF8-418E-B205-FB04D23E0312}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6A9E4125-03D1-4DAF-8333-336C49360621}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6A9E4125-03D1-4DAF-8333-336C49360621}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6A9E4125-03D1-4DAF-8333-336C49360621}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6A9E4125-03D1-4DAF-8333-336C49360621}.Release|Any CPU.Build.0 = Release|Any CPU
-		{1BA7884A-3D6F-4479-A0F9-44385662FE24}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{1BA7884A-3D6F-4479-A0F9-44385662FE24}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{1BA7884A-3D6F-4479-A0F9-44385662FE24}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{1BA7884A-3D6F-4479-A0F9-44385662FE24}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FBE7E7D4-EBF1-4B0C-B63E-540DA1C9CEAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FBE7E7D4-EBF1-4B0C-B63E-540DA1C9CEAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FBE7E7D4-EBF1-4B0C-B63E-540DA1C9CEAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FBE7E7D4-EBF1-4B0C-B63E-540DA1C9CEAA}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7E047279-FD70-440F-8FB9-B47E88747EF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7E047279-FD70-440F-8FB9-B47E88747EF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7E047279-FD70-440F-8FB9-B47E88747EF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7E047279-FD70-440F-8FB9-B47E88747EF4}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A60E1C9A-6E52-42F7-ACA2-BB58DA64361E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A60E1C9A-6E52-42F7-ACA2-BB58DA64361E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A60E1C9A-6E52-42F7-ACA2-BB58DA64361E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A60E1C9A-6E52-42F7-ACA2-BB58DA64361E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{427A9EFA-5E06-4176-A287-0DC0E0CD3E86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{427A9EFA-5E06-4176-A287-0DC0E0CD3E86}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{427A9EFA-5E06-4176-A287-0DC0E0CD3E86}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{427A9EFA-5E06-4176-A287-0DC0E0CD3E86}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4B864ACE-495C-46FB-870F-4D794C02C8F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4B864ACE-495C-46FB-870F-4D794C02C8F9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4B864ACE-495C-46FB-870F-4D794C02C8F9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4B864ACE-495C-46FB-870F-4D794C02C8F9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{17419CBD-2AC6-479F-ACA7-D478F9FBF397}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{17419CBD-2AC6-479F-ACA7-D478F9FBF397}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{17419CBD-2AC6-479F-ACA7-D478F9FBF397}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{17419CBD-2AC6-479F-ACA7-D478F9FBF397}.Release|Any CPU.Build.0 = Release|Any CPU
-		{03856292-CE47-45EE-91D4-6ACF27E1925F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{03856292-CE47-45EE-91D4-6ACF27E1925F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{03856292-CE47-45EE-91D4-6ACF27E1925F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{03856292-CE47-45EE-91D4-6ACF27E1925F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{762A1A84-4B1E-49A1-BC58-4988BB489F7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{762A1A84-4B1E-49A1-BC58-4988BB489F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{762A1A84-4B1E-49A1-BC58-4988BB489F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{762A1A84-4B1E-49A1-BC58-4988BB489F7C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3B42D204-BFB1-456F-B5F5-9421EECE465A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3B42D204-BFB1-456F-B5F5-9421EECE465A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3B42D204-BFB1-456F-B5F5-9421EECE465A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3B42D204-BFB1-456F-B5F5-9421EECE465A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F8BC96E4-15E2-4F64-9D25-E167EC207404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F8BC96E4-15E2-4F64-9D25-E167EC207404}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F8BC96E4-15E2-4F64-9D25-E167EC207404}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F8BC96E4-15E2-4F64-9D25-E167EC207404}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A2EB7FD7-7660-4297-B431-9833CB65A848}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A2EB7FD7-7660-4297-B431-9833CB65A848}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A2EB7FD7-7660-4297-B431-9833CB65A848}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A2EB7FD7-7660-4297-B431-9833CB65A848}.Release|Any CPU.Build.0 = Release|Any CPU
-		{086D5907-AAF8-4488-A2AD-4A3430D74FAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{086D5907-AAF8-4488-A2AD-4A3430D74FAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{086D5907-AAF8-4488-A2AD-4A3430D74FAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{086D5907-AAF8-4488-A2AD-4A3430D74FAB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6ACF8F5B-B1E1-439B-AFFF-42D6B143760E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6ACF8F5B-B1E1-439B-AFFF-42D6B143760E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6ACF8F5B-B1E1-439B-AFFF-42D6B143760E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6ACF8F5B-B1E1-439B-AFFF-42D6B143760E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{50FB388F-6D68-400C-A919-0414B87466A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{50FB388F-6D68-400C-A919-0414B87466A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{50FB388F-6D68-400C-A919-0414B87466A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{50FB388F-6D68-400C-A919-0414B87466A7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F1957BE5-4CA4-494B-A62B-AA4F5E4D460A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F1957BE5-4CA4-494B-A62B-AA4F5E4D460A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F1957BE5-4CA4-494B-A62B-AA4F5E4D460A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F1957BE5-4CA4-494B-A62B-AA4F5E4D460A}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F2077E7E-7305-4FC7-8D67-D90037B3F370}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F2077E7E-7305-4FC7-8D67-D90037B3F370}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F2077E7E-7305-4FC7-8D67-D90037B3F370}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F2077E7E-7305-4FC7-8D67-D90037B3F370}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3A3D27B8-10FE-4E72-A3CE-183EBC11503B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3A3D27B8-10FE-4E72-A3CE-183EBC11503B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3A3D27B8-10FE-4E72-A3CE-183EBC11503B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3A3D27B8-10FE-4E72-A3CE-183EBC11503B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A8777E05-E344-4673-915B-E9224002C423}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A8777E05-E344-4673-915B-E9224002C423}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A8777E05-E344-4673-915B-E9224002C423}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A8777E05-E344-4673-915B-E9224002C423}.Release|Any CPU.Build.0 = Release|Any CPU
-		{05B08A0C-5BCA-4FF6-9C42-9DFF5E7DCDEA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{05B08A0C-5BCA-4FF6-9C42-9DFF5E7DCDEA}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{05B08A0C-5BCA-4FF6-9C42-9DFF5E7DCDEA}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{05B08A0C-5BCA-4FF6-9C42-9DFF5E7DCDEA}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C9CFE66E-6921-4CCE-83A7-D5B54812122F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C9CFE66E-6921-4CCE-83A7-D5B54812122F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C9CFE66E-6921-4CCE-83A7-D5B54812122F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C9CFE66E-6921-4CCE-83A7-D5B54812122F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{A0FD4472-99E5-4FBC-A6A7-20786EA167DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{A0FD4472-99E5-4FBC-A6A7-20786EA167DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{A0FD4472-99E5-4FBC-A6A7-20786EA167DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{A0FD4472-99E5-4FBC-A6A7-20786EA167DF}.Release|Any CPU.Build.0 = Release|Any CPU
-		{86272012-C994-41F7-BFAF-4BED50797B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{86272012-C994-41F7-BFAF-4BED50797B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{86272012-C994-41F7-BFAF-4BED50797B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{86272012-C994-41F7-BFAF-4BED50797B22}.Release|Any CPU.Build.0 = Release|Any CPU
-		{94B89563-1E74-42F9-96A5-19CD800AFECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{94B89563-1E74-42F9-96A5-19CD800AFECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{94B89563-1E74-42F9-96A5-19CD800AFECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{94B89563-1E74-42F9-96A5-19CD800AFECB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{E5D2964E-CFE9-4DE6-99B5-1F54F9984F65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{E5D2964E-CFE9-4DE6-99B5-1F54F9984F65}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{E5D2964E-CFE9-4DE6-99B5-1F54F9984F65}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{E5D2964E-CFE9-4DE6-99B5-1F54F9984F65}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C92F8E81-6FB1-46FF-9B68-2D126F8903E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C92F8E81-6FB1-46FF-9B68-2D126F8903E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C92F8E81-6FB1-46FF-9B68-2D126F8903E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C92F8E81-6FB1-46FF-9B68-2D126F8903E6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B9207BE6-2577-4C49-AF5F-130A17BBEA73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B9207BE6-2577-4C49-AF5F-130A17BBEA73}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B9207BE6-2577-4C49-AF5F-130A17BBEA73}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B9207BE6-2577-4C49-AF5F-130A17BBEA73}.Release|Any CPU.Build.0 = Release|Any CPU
-		{40C19FFA-E1E1-4589-86E4-B7BEF336CE79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{40C19FFA-E1E1-4589-86E4-B7BEF336CE79}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{40C19FFA-E1E1-4589-86E4-B7BEF336CE79}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{40C19FFA-E1E1-4589-86E4-B7BEF336CE79}.Release|Any CPU.Build.0 = Release|Any CPU
-		{64324C38-03F7-4624-8F00-B85183DDBF99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{64324C38-03F7-4624-8F00-B85183DDBF99}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{64324C38-03F7-4624-8F00-B85183DDBF99}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{64324C38-03F7-4624-8F00-B85183DDBF99}.Release|Any CPU.Build.0 = Release|Any CPU
-		{14C24193-D5E0-4D29-B270-C27B43CC1925}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{14C24193-D5E0-4D29-B270-C27B43CC1925}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{14C24193-D5E0-4D29-B270-C27B43CC1925}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{14C24193-D5E0-4D29-B270-C27B43CC1925}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B25208A4-3C80-411E-A36A-7BC4AA506DC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B25208A4-3C80-411E-A36A-7BC4AA506DC7}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B25208A4-3C80-411E-A36A-7BC4AA506DC7}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B25208A4-3C80-411E-A36A-7BC4AA506DC7}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2A56B16C-3980-4380-84E8-B20DEEEFB5D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2A56B16C-3980-4380-84E8-B20DEEEFB5D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2A56B16C-3980-4380-84E8-B20DEEEFB5D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2A56B16C-3980-4380-84E8-B20DEEEFB5D6}.Release|Any CPU.Build.0 = Release|Any CPU
-		{269971FF-B748-4B95-8507-534C229A60B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{269971FF-B748-4B95-8507-534C229A60B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{269971FF-B748-4B95-8507-534C229A60B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{269971FF-B748-4B95-8507-534C229A60B9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F6244150-1AD9-470E-B0F0-72389B10639E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F6244150-1AD9-470E-B0F0-72389B10639E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F6244150-1AD9-470E-B0F0-72389B10639E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F6244150-1AD9-470E-B0F0-72389B10639E}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D1102F23-265A-4CA8-975C-75564DFFAA04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D1102F23-265A-4CA8-975C-75564DFFAA04}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D1102F23-265A-4CA8-975C-75564DFFAA04}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D1102F23-265A-4CA8-975C-75564DFFAA04}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F4C5ECB6-2C17-4BC9-BF8F-BA9117BD2843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F4C5ECB6-2C17-4BC9-BF8F-BA9117BD2843}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F4C5ECB6-2C17-4BC9-BF8F-BA9117BD2843}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F4C5ECB6-2C17-4BC9-BF8F-BA9117BD2843}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B9C4BF5F-2D56-4B06-A1EE-1E1CC642D14B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B9C4BF5F-2D56-4B06-A1EE-1E1CC642D14B}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B9C4BF5F-2D56-4B06-A1EE-1E1CC642D14B}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B9C4BF5F-2D56-4B06-A1EE-1E1CC642D14B}.Release|Any CPU.Build.0 = Release|Any CPU
-		{6CE987BF-9677-476C-8BB9-1BE7CC16F932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{6CE987BF-9677-476C-8BB9-1BE7CC16F932}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{6CE987BF-9677-476C-8BB9-1BE7CC16F932}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{6CE987BF-9677-476C-8BB9-1BE7CC16F932}.Release|Any CPU.Build.0 = Release|Any CPU
-		{BD63E691-0A53-46CE-B687-E3CD95F1D4B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{BD63E691-0A53-46CE-B687-E3CD95F1D4B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{BD63E691-0A53-46CE-B687-E3CD95F1D4B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{BD63E691-0A53-46CE-B687-E3CD95F1D4B1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{FCF9AB0E-4310-4BCB-8682-833450658B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{FCF9AB0E-4310-4BCB-8682-833450658B97}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{FCF9AB0E-4310-4BCB-8682-833450658B97}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{FCF9AB0E-4310-4BCB-8682-833450658B97}.Release|Any CPU.Build.0 = Release|Any CPU
-		{607AB17F-1305-4002-A980-DB60699688F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{607AB17F-1305-4002-A980-DB60699688F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{607AB17F-1305-4002-A980-DB60699688F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{607AB17F-1305-4002-A980-DB60699688F1}.Release|Any CPU.Build.0 = Release|Any CPU
-		{128B3A5D-E28C-4C7F-8B16-3202D0F73A00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{128B3A5D-E28C-4C7F-8B16-3202D0F73A00}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{128B3A5D-E28C-4C7F-8B16-3202D0F73A00}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{128B3A5D-E28C-4C7F-8B16-3202D0F73A00}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B98F63AB-F0C8-4594-98BD-0BBBAEA4C4E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B98F63AB-F0C8-4594-98BD-0BBBAEA4C4E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B98F63AB-F0C8-4594-98BD-0BBBAEA4C4E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B98F63AB-F0C8-4594-98BD-0BBBAEA4C4E9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{62EBA4E5-BD13-4F7C-85E6-65D633B3FB6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{62EBA4E5-BD13-4F7C-85E6-65D633B3FB6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{62EBA4E5-BD13-4F7C-85E6-65D633B3FB6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{62EBA4E5-BD13-4F7C-85E6-65D633B3FB6C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{DFE95B37-24F5-417A-8C3F-788255CE8A04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{DFE95B37-24F5-417A-8C3F-788255CE8A04}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{DFE95B37-24F5-417A-8C3F-788255CE8A04}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{DFE95B37-24F5-417A-8C3F-788255CE8A04}.Release|Any CPU.Build.0 = Release|Any CPU
-		{77E253C3-5FCE-45A4-B285-BE24945E0D70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{77E253C3-5FCE-45A4-B285-BE24945E0D70}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{77E253C3-5FCE-45A4-B285-BE24945E0D70}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{77E253C3-5FCE-45A4-B285-BE24945E0D70}.Release|Any CPU.Build.0 = Release|Any CPU
-		{32ECF281-6D99-42D4-AD00-C8B56A8270F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{32ECF281-6D99-42D4-AD00-C8B56A8270F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{32ECF281-6D99-42D4-AD00-C8B56A8270F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{32ECF281-6D99-42D4-AD00-C8B56A8270F8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2EBD1C45-9D80-413A-9BE8-4ECB43C06843}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2EBD1C45-9D80-413A-9BE8-4ECB43C06843}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2EBD1C45-9D80-413A-9BE8-4ECB43C06843}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2EBD1C45-9D80-413A-9BE8-4ECB43C06843}.Release|Any CPU.Build.0 = Release|Any CPU
-		{79198D56-C3F2-49D6-B8BF-5BB674B6F7A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{79198D56-C3F2-49D6-B8BF-5BB674B6F7A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{79198D56-C3F2-49D6-B8BF-5BB674B6F7A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{79198D56-C3F2-49D6-B8BF-5BB674B6F7A2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{83504141-FF2A-427E-8A51-9FA0E9037A78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{83504141-FF2A-427E-8A51-9FA0E9037A78}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{83504141-FF2A-427E-8A51-9FA0E9037A78}.Release|Any CPU.Build.0 = Release|Any CPU
-		{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{DF67FD2D-4897-43C5-A93E-7CCADBB29E75}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4B862F51-054D-467F-971D-8A7B72F5B498}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4B862F51-054D-467F-971D-8A7B72F5B498}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4B862F51-054D-467F-971D-8A7B72F5B498}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4B862F51-054D-467F-971D-8A7B72F5B498}.Release|Any CPU.Build.0 = Release|Any CPU
-		{05EF2C70-B5B0-4351-B940-041A03A6BB84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{05EF2C70-B5B0-4351-B940-041A03A6BB84}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{05EF2C70-B5B0-4351-B940-041A03A6BB84}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{05EF2C70-B5B0-4351-B940-041A03A6BB84}.Release|Any CPU.Build.0 = Release|Any CPU
-		{18BC2EE7-E798-40DE-A346-0B803137E67D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{18BC2EE7-E798-40DE-A346-0B803137E67D}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{18BC2EE7-E798-40DE-A346-0B803137E67D}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{18BC2EE7-E798-40DE-A346-0B803137E67D}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D0399EAC-5563-4234-9828-0C607BAF7623}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D0399EAC-5563-4234-9828-0C607BAF7623}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D0399EAC-5563-4234-9828-0C607BAF7623}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D0399EAC-5563-4234-9828-0C607BAF7623}.Release|Any CPU.Build.0 = Release|Any CPU
-		{72432190-8D4D-4E64-B622-F83BE80A3CBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{72432190-8D4D-4E64-B622-F83BE80A3CBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{72432190-8D4D-4E64-B622-F83BE80A3CBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{72432190-8D4D-4E64-B622-F83BE80A3CBB}.Release|Any CPU.Build.0 = Release|Any CPU
-		{D2105979-EE3B-432B-8016-172BA949DE2F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{D2105979-EE3B-432B-8016-172BA949DE2F}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{D2105979-EE3B-432B-8016-172BA949DE2F}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{D2105979-EE3B-432B-8016-172BA949DE2F}.Release|Any CPU.Build.0 = Release|Any CPU
-		{7015C2C4-4050-4631-9394-7EAF19AB0191}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{7015C2C4-4050-4631-9394-7EAF19AB0191}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{7015C2C4-4050-4631-9394-7EAF19AB0191}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{7015C2C4-4050-4631-9394-7EAF19AB0191}.Release|Any CPU.Build.0 = Release|Any CPU
-		{C029D4C6-3A10-459E-96D7-3E77170A5A10}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{C029D4C6-3A10-459E-96D7-3E77170A5A10}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{C029D4C6-3A10-459E-96D7-3E77170A5A10}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{C029D4C6-3A10-459E-96D7-3E77170A5A10}.Release|Any CPU.Build.0 = Release|Any CPU
-		{0CBB430D-BF64-436F-93BE-8E8088DBCBFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{0CBB430D-BF64-436F-93BE-8E8088DBCBFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{0CBB430D-BF64-436F-93BE-8E8088DBCBFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{0CBB430D-BF64-436F-93BE-8E8088DBCBFE}.Release|Any CPU.Build.0 = Release|Any CPU
-		{758DDF02-FFE7-4A4A-BD7C-0B189F3257C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{758DDF02-FFE7-4A4A-BD7C-0B189F3257C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{758DDF02-FFE7-4A4A-BD7C-0B189F3257C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{758DDF02-FFE7-4A4A-BD7C-0B189F3257C9}.Release|Any CPU.Build.0 = Release|Any CPU
-		{DFF04F1E-2963-4A88-AF92-D14AD48617F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{DFF04F1E-2963-4A88-AF92-D14AD48617F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{DFF04F1E-2963-4A88-AF92-D14AD48617F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{DFF04F1E-2963-4A88-AF92-D14AD48617F2}.Release|Any CPU.Build.0 = Release|Any CPU
-		{202E2755-AB2F-4EA5-94D0-574487079CFF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{202E2755-AB2F-4EA5-94D0-574487079CFF}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{202E2755-AB2F-4EA5-94D0-574487079CFF}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{202E2755-AB2F-4EA5-94D0-574487079CFF}.Release|Any CPU.Build.0 = Release|Any CPU
-		{B287CA86-D25C-40B0-98B9-855064F99EE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{B287CA86-D25C-40B0-98B9-855064F99EE3}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{B287CA86-D25C-40B0-98B9-855064F99EE3}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{B287CA86-D25C-40B0-98B9-855064F99EE3}.Release|Any CPU.Build.0 = Release|Any CPU
-		{91499710-DC6A-4494-9661-9D374829E975}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{91499710-DC6A-4494-9661-9D374829E975}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{91499710-DC6A-4494-9661-9D374829E975}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{91499710-DC6A-4494-9661-9D374829E975}.Release|Any CPU.Build.0 = Release|Any CPU
-		{3E499D5B-C5A9-4BCD-BF35-46D590EC06AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{3E499D5B-C5A9-4BCD-BF35-46D590EC06AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{3E499D5B-C5A9-4BCD-BF35-46D590EC06AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{3E499D5B-C5A9-4BCD-BF35-46D590EC06AD}.Release|Any CPU.Build.0 = Release|Any CPU
-		{F16F1FD4-2B74-4E90-83D1-0614843FDF62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{F16F1FD4-2B74-4E90-83D1-0614843FDF62}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{F16F1FD4-2B74-4E90-83D1-0614843FDF62}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{F16F1FD4-2B74-4E90-83D1-0614843FDF62}.Release|Any CPU.Build.0 = Release|Any CPU
-		{667D7B20-F14D-4129-9BBD-F9F5A0D66A9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{667D7B20-F14D-4129-9BBD-F9F5A0D66A9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{667D7B20-F14D-4129-9BBD-F9F5A0D66A9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{667D7B20-F14D-4129-9BBD-F9F5A0D66A9E}.Release|Any CPU.Build.0 = Release|Any CPU
-	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {A9C4E72E-BB5B-4EAD-B0E6-4845EB77019B}
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{DBDE9159-2423-4473-9853-4101095D93A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DBDE9159-2423-4473-9853-4101095D93A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DBDE9159-2423-4473-9853-4101095D93A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DBDE9159-2423-4473-9853-4101095D93A2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{758FC429-A223-439E-B4C4-3FC5E318468C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{758FC429-A223-439E-B4C4-3FC5E318468C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{758FC429-A223-439E-B4C4-3FC5E318468C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{758FC429-A223-439E-B4C4-3FC5E318468C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F185E45E-9806-4617-BF97-635FCEB61680}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F185E45E-9806-4617-BF97-635FCEB61680}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F185E45E-9806-4617-BF97-635FCEB61680}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F185E45E-9806-4617-BF97-635FCEB61680}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{331F0F1E-6A35-4E22-BBFA-004A1D4EE757}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{331F0F1E-6A35-4E22-BBFA-004A1D4EE757}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{331F0F1E-6A35-4E22-BBFA-004A1D4EE757}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{331F0F1E-6A35-4E22-BBFA-004A1D4EE757}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1B613B04-C002-48F8-B320-EA7BCC8483A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1B613B04-C002-48F8-B320-EA7BCC8483A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1B613B04-C002-48F8-B320-EA7BCC8483A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1B613B04-C002-48F8-B320-EA7BCC8483A7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BA955D45-C36D-4CDC-A0BA-708432C63B3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BA955D45-C36D-4CDC-A0BA-708432C63B3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BA955D45-C36D-4CDC-A0BA-708432C63B3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BA955D45-C36D-4CDC-A0BA-708432C63B3E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1C829A36-C841-4BD6-993D-1F6EA3998B12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1C829A36-C841-4BD6-993D-1F6EA3998B12}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1C829A36-C841-4BD6-993D-1F6EA3998B12}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1C829A36-C841-4BD6-993D-1F6EA3998B12}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E55BB790-87EC-4C8E-9908-8D0C01E5C215}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E55BB790-87EC-4C8E-9908-8D0C01E5C215}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E55BB790-87EC-4C8E-9908-8D0C01E5C215}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E55BB790-87EC-4C8E-9908-8D0C01E5C215}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E3D46015-AB12-47AB-AB37-5FFF5B781BD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E3D46015-AB12-47AB-AB37-5FFF5B781BD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E3D46015-AB12-47AB-AB37-5FFF5B781BD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E3D46015-AB12-47AB-AB37-5FFF5B781BD9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{62F13963-52BC-4513-B2F5-ED5E07146860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{62F13963-52BC-4513-B2F5-ED5E07146860}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{62F13963-52BC-4513-B2F5-ED5E07146860}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{62F13963-52BC-4513-B2F5-ED5E07146860}.Release|Any CPU.Build.0 = Release|Any CPU
+		{17A5BDBE-C1D1-452E-8627-CE492B3E56BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{17A5BDBE-C1D1-452E-8627-CE492B3E56BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{17A5BDBE-C1D1-452E-8627-CE492B3E56BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{17A5BDBE-C1D1-452E-8627-CE492B3E56BE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9557D34F-A76C-4A04-92F6-7769676C60B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9557D34F-A76C-4A04-92F6-7769676C60B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9557D34F-A76C-4A04-92F6-7769676C60B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9557D34F-A76C-4A04-92F6-7769676C60B1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{22D6F789-FE96-48DB-ACC1-3A52664B9F9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{22D6F789-FE96-48DB-ACC1-3A52664B9F9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{22D6F789-FE96-48DB-ACC1-3A52664B9F9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{22D6F789-FE96-48DB-ACC1-3A52664B9F9E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F72896F4-43E6-4FBC-8D7D-D0306657DE34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F72896F4-43E6-4FBC-8D7D-D0306657DE34}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F72896F4-43E6-4FBC-8D7D-D0306657DE34}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F72896F4-43E6-4FBC-8D7D-D0306657DE34}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B512C62C-677E-4A07-8B96-E973005501E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B512C62C-677E-4A07-8B96-E973005501E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B512C62C-677E-4A07-8B96-E973005501E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B512C62C-677E-4A07-8B96-E973005501E6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3B766FF7-0B73-409C-AC9F-833FA152BD0C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3B766FF7-0B73-409C-AC9F-833FA152BD0C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3B766FF7-0B73-409C-AC9F-833FA152BD0C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3B766FF7-0B73-409C-AC9F-833FA152BD0C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FB29A674-B8AC-4A1E-9D64-6DC151E7884E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FB29A674-B8AC-4A1E-9D64-6DC151E7884E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FB29A674-B8AC-4A1E-9D64-6DC151E7884E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FB29A674-B8AC-4A1E-9D64-6DC151E7884E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{842EF7A8-F305-42BC-8740-9ABB58202606}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{842EF7A8-F305-42BC-8740-9ABB58202606}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{842EF7A8-F305-42BC-8740-9ABB58202606}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{842EF7A8-F305-42BC-8740-9ABB58202606}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F67A2623-4C33-46D4-9CE3-827C59240089}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F67A2623-4C33-46D4-9CE3-827C59240089}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F67A2623-4C33-46D4-9CE3-827C59240089}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F67A2623-4C33-46D4-9CE3-827C59240089}.Release|Any CPU.Build.0 = Release|Any CPU
+		{86830781-83E7-40D4-AC04-9F8CB730C5CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{86830781-83E7-40D4-AC04-9F8CB730C5CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{86830781-83E7-40D4-AC04-9F8CB730C5CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{86830781-83E7-40D4-AC04-9F8CB730C5CF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{42F380C0-9B44-40FD-8F15-19D949CCB2BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{42F380C0-9B44-40FD-8F15-19D949CCB2BD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{42F380C0-9B44-40FD-8F15-19D949CCB2BD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{42F380C0-9B44-40FD-8F15-19D949CCB2BD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{85B57E4B-C0CC-45A2-BA93-A10302AC9080}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{85B57E4B-C0CC-45A2-BA93-A10302AC9080}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{85B57E4B-C0CC-45A2-BA93-A10302AC9080}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{85B57E4B-C0CC-45A2-BA93-A10302AC9080}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F85A785C-195A-4B88-9563-6AFED7D8A398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F85A785C-195A-4B88-9563-6AFED7D8A398}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F85A785C-195A-4B88-9563-6AFED7D8A398}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F85A785C-195A-4B88-9563-6AFED7D8A398}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FC58281F-374A-4C48-B00E-BB46D6EE2B89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FC58281F-374A-4C48-B00E-BB46D6EE2B89}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FC58281F-374A-4C48-B00E-BB46D6EE2B89}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FC58281F-374A-4C48-B00E-BB46D6EE2B89}.Release|Any CPU.Build.0 = Release|Any CPU
+		{48E8B6EF-A590-417C-B7B9-A6345FCD70A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{48E8B6EF-A590-417C-B7B9-A6345FCD70A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{48E8B6EF-A590-417C-B7B9-A6345FCD70A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{48E8B6EF-A590-417C-B7B9-A6345FCD70A0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D9D540F8-AEAA-4076-A5A5-5711FC451D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D9D540F8-AEAA-4076-A5A5-5711FC451D99}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D9D540F8-AEAA-4076-A5A5-5711FC451D99}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D9D540F8-AEAA-4076-A5A5-5711FC451D99}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7F321163-AD3F-4F08-83B9-714BDA5FE088}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7F321163-AD3F-4F08-83B9-714BDA5FE088}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7F321163-AD3F-4F08-83B9-714BDA5FE088}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7F321163-AD3F-4F08-83B9-714BDA5FE088}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3329B3ED-C681-4BA4-9947-5F152A38FD0D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3329B3ED-C681-4BA4-9947-5F152A38FD0D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3329B3ED-C681-4BA4-9947-5F152A38FD0D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3329B3ED-C681-4BA4-9947-5F152A38FD0D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442}.Release|Any CPU.Build.0 = Release|Any CPU
+		{684FA1FC-5BA3-4089-B6C4-5E6797D463C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{684FA1FC-5BA3-4089-B6C4-5E6797D463C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{684FA1FC-5BA3-4089-B6C4-5E6797D463C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{684FA1FC-5BA3-4089-B6C4-5E6797D463C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{863F435B-B7C7-4CC8-9A4F-2267385B8487}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{863F435B-B7C7-4CC8-9A4F-2267385B8487}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{863F435B-B7C7-4CC8-9A4F-2267385B8487}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{863F435B-B7C7-4CC8-9A4F-2267385B8487}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FBDEECDC-AF92-42B3-AE69-3AF91F26F683}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FBDEECDC-AF92-42B3-AE69-3AF91F26F683}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FBDEECDC-AF92-42B3-AE69-3AF91F26F683}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FBDEECDC-AF92-42B3-AE69-3AF91F26F683}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BE366E7A-F7C8-4AB2-9928-04FC68238883}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BE366E7A-F7C8-4AB2-9928-04FC68238883}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BE366E7A-F7C8-4AB2-9928-04FC68238883}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BE366E7A-F7C8-4AB2-9928-04FC68238883}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A405FB21-249D-4F71-A46E-D943021BA33F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A405FB21-249D-4F71-A46E-D943021BA33F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A405FB21-249D-4F71-A46E-D943021BA33F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A405FB21-249D-4F71-A46E-D943021BA33F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{54EBB5D5-B14C-4297-945E-1A3C11B51740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{54EBB5D5-B14C-4297-945E-1A3C11B51740}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{54EBB5D5-B14C-4297-945E-1A3C11B51740}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{54EBB5D5-B14C-4297-945E-1A3C11B51740}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A6CE175A-285A-40C1-ABA8-90A9E483FB70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A6CE175A-285A-40C1-ABA8-90A9E483FB70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A6CE175A-285A-40C1-ABA8-90A9E483FB70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A6CE175A-285A-40C1-ABA8-90A9E483FB70}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3B0DA602-0415-408E-A3AC-84B3EC23DE13}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3B0DA602-0415-408E-A3AC-84B3EC23DE13}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3B0DA602-0415-408E-A3AC-84B3EC23DE13}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3B0DA602-0415-408E-A3AC-84B3EC23DE13}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EB3333ED-3B41-4C2A-A979-C224E4B7C646}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EB3333ED-3B41-4C2A-A979-C224E4B7C646}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EB3333ED-3B41-4C2A-A979-C224E4B7C646}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EB3333ED-3B41-4C2A-A979-C224E4B7C646}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1FD342FB-67C0-4A93-8DCE-93180CAF38A2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1FD342FB-67C0-4A93-8DCE-93180CAF38A2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1FD342FB-67C0-4A93-8DCE-93180CAF38A2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1FD342FB-67C0-4A93-8DCE-93180CAF38A2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F74F4279-B424-49A9-A539-909FD5298A04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F74F4279-B424-49A9-A539-909FD5298A04}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F74F4279-B424-49A9-A539-909FD5298A04}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F74F4279-B424-49A9-A539-909FD5298A04}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5A24CA2C-7E8F-4123-9B2C-9866957A76B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5A24CA2C-7E8F-4123-9B2C-9866957A76B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5A24CA2C-7E8F-4123-9B2C-9866957A76B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5A24CA2C-7E8F-4123-9B2C-9866957A76B9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B9285667-4EBE-4EF7-AB66-396F8651BDAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B9285667-4EBE-4EF7-AB66-396F8651BDAD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B9285667-4EBE-4EF7-AB66-396F8651BDAD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B9285667-4EBE-4EF7-AB66-396F8651BDAD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{97E48A24-B5CB-478E-AF2A-B8FB2350DB12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{97E48A24-B5CB-478E-AF2A-B8FB2350DB12}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{97E48A24-B5CB-478E-AF2A-B8FB2350DB12}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{97E48A24-B5CB-478E-AF2A-B8FB2350DB12}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CB9E0567-82A1-4E03-95B9-8397A80A7144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CB9E0567-82A1-4E03-95B9-8397A80A7144}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CB9E0567-82A1-4E03-95B9-8397A80A7144}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CB9E0567-82A1-4E03-95B9-8397A80A7144}.Release|Any CPU.Build.0 = Release|Any CPU
+		{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7628BE7F-AD0D-4C08-95FF-907E78593169}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7628BE7F-AD0D-4C08-95FF-907E78593169}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7628BE7F-AD0D-4C08-95FF-907E78593169}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7628BE7F-AD0D-4C08-95FF-907E78593169}.Release|Any CPU.Build.0 = Release|Any CPU
+		{21C347CC-D097-4B78-8B2D-9763B3FA868E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{21C347CC-D097-4B78-8B2D-9763B3FA868E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{21C347CC-D097-4B78-8B2D-9763B3FA868E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{21C347CC-D097-4B78-8B2D-9763B3FA868E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{78FBF12B-FF17-4FAB-A51C-375DFB376A84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{78FBF12B-FF17-4FAB-A51C-375DFB376A84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{78FBF12B-FF17-4FAB-A51C-375DFB376A84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{78FBF12B-FF17-4FAB-A51C-375DFB376A84}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6E91AA59-BD05-49EC-8DEA-C69542C8438F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6E91AA59-BD05-49EC-8DEA-C69542C8438F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6E91AA59-BD05-49EC-8DEA-C69542C8438F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6E91AA59-BD05-49EC-8DEA-C69542C8438F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A680BF33-6C6E-4093-84C1-813C51BDA1E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A680BF33-6C6E-4093-84C1-813C51BDA1E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A680BF33-6C6E-4093-84C1-813C51BDA1E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A680BF33-6C6E-4093-84C1-813C51BDA1E7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4BC37EC1-225E-4949-AAE0-44E3DCE0E141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4BC37EC1-225E-4949-AAE0-44E3DCE0E141}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4BC37EC1-225E-4949-AAE0-44E3DCE0E141}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4BC37EC1-225E-4949-AAE0-44E3DCE0E141}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C43D0602-7C1C-46BA-B4C4-FBC1C1428859}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C43D0602-7C1C-46BA-B4C4-FBC1C1428859}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C43D0602-7C1C-46BA-B4C4-FBC1C1428859}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C43D0602-7C1C-46BA-B4C4-FBC1C1428859}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833}.Release|Any CPU.Build.0 = Release|Any CPU
+		{53713CF1-576B-480A-B40A-1753A4A90CC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{53713CF1-576B-480A-B40A-1753A4A90CC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{53713CF1-576B-480A-B40A-1753A4A90CC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{53713CF1-576B-480A-B40A-1753A4A90CC3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EF104B33-8F43-458A-9533-597CF8389004}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EF104B33-8F43-458A-9533-597CF8389004}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EF104B33-8F43-458A-9533-597CF8389004}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EF104B33-8F43-458A-9533-597CF8389004}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6}.Release|Any CPU.Build.0 = Release|Any CPU
+		{802FAF1C-3A5E-44D9-8D0A-ED292579CF00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{802FAF1C-3A5E-44D9-8D0A-ED292579CF00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{802FAF1C-3A5E-44D9-8D0A-ED292579CF00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{802FAF1C-3A5E-44D9-8D0A-ED292579CF00}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E582C914-C7B0-4812-92DE-7849F485EAD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E582C914-C7B0-4812-92DE-7849F485EAD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E582C914-C7B0-4812-92DE-7849F485EAD4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E582C914-C7B0-4812-92DE-7849F485EAD4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FFE3F9EB-D6F9-47EE-AA5F-486053610D80}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FFE3F9EB-D6F9-47EE-AA5F-486053610D80}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FFE3F9EB-D6F9-47EE-AA5F-486053610D80}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FFE3F9EB-D6F9-47EE-AA5F-486053610D80}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A901A7DB-5CAC-4245-9920-6BC28DCC94D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A901A7DB-5CAC-4245-9920-6BC28DCC94D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A901A7DB-5CAC-4245-9920-6BC28DCC94D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A901A7DB-5CAC-4245-9920-6BC28DCC94D8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{0DA78D58-5ABC-4C33-B390-A3022E815B36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{0DA78D58-5ABC-4C33-B390-A3022E815B36}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{0DA78D58-5ABC-4C33-B390-A3022E815B36}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{0DA78D58-5ABC-4C33-B390-A3022E815B36}.Release|Any CPU.Build.0 = Release|Any CPU
+		{89D0A49C-D534-4DE0-8357-75F8AE363994}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{89D0A49C-D534-4DE0-8357-75F8AE363994}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{89D0A49C-D534-4DE0-8357-75F8AE363994}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{89D0A49C-D534-4DE0-8357-75F8AE363994}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A340652C-93D8-42AB-8724-08A0BC737A05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A340652C-93D8-42AB-8724-08A0BC737A05}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A340652C-93D8-42AB-8724-08A0BC737A05}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A340652C-93D8-42AB-8724-08A0BC737A05}.Release|Any CPU.Build.0 = Release|Any CPU
+		{58B4C338-F610-4227-8685-DD04393587A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{58B4C338-F610-4227-8685-DD04393587A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{58B4C338-F610-4227-8685-DD04393587A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{58B4C338-F610-4227-8685-DD04393587A0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{672CEA36-D471-4ECA-9FB4-CE4576835A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{672CEA36-D471-4ECA-9FB4-CE4576835A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{672CEA36-D471-4ECA-9FB4-CE4576835A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{672CEA36-D471-4ECA-9FB4-CE4576835A28}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{37A064B1-AB4D-4137-B912-B6D358407A26}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{37A064B1-AB4D-4137-B912-B6D358407A26}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{37A064B1-AB4D-4137-B912-B6D358407A26}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{37A064B1-AB4D-4137-B912-B6D358407A26}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D0D3DDF6-5338-4751-BA6E-8D64A77201B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D0D3DDF6-5338-4751-BA6E-8D64A77201B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D0D3DDF6-5338-4751-BA6E-8D64A77201B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D0D3DDF6-5338-4751-BA6E-8D64A77201B9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{23101060-4031-4158-92F2-0E4995C24ADE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{23101060-4031-4158-92F2-0E4995C24ADE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{23101060-4031-4158-92F2-0E4995C24ADE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{23101060-4031-4158-92F2-0E4995C24ADE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9D5AF8C8-791B-47F1-986D-27900531B594}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9D5AF8C8-791B-47F1-986D-27900531B594}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9D5AF8C8-791B-47F1-986D-27900531B594}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9D5AF8C8-791B-47F1-986D-27900531B594}.Release|Any CPU.Build.0 = Release|Any CPU
+		{EE8DC120-142D-40EE-A846-2BB56BEA4608}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{EE8DC120-142D-40EE-A846-2BB56BEA4608}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{EE8DC120-142D-40EE-A846-2BB56BEA4608}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{EE8DC120-142D-40EE-A846-2BB56BEA4608}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6F459E05-765F-4DBA-82E3-EAD6A4B2874C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6F459E05-765F-4DBA-82E3-EAD6A4B2874C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6F459E05-765F-4DBA-82E3-EAD6A4B2874C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6F459E05-765F-4DBA-82E3-EAD6A4B2874C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D06A3406-D4CF-4317-BEB6-A631CB3F51DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D06A3406-D4CF-4317-BEB6-A631CB3F51DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D06A3406-D4CF-4317-BEB6-A631CB3F51DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D06A3406-D4CF-4317-BEB6-A631CB3F51DC}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B037C0BA-CE27-4C1D-A869-65FF4C4A5689}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B037C0BA-CE27-4C1D-A869-65FF4C4A5689}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B037C0BA-CE27-4C1D-A869-65FF4C4A5689}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B037C0BA-CE27-4C1D-A869-65FF4C4A5689}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CB025E4C-ED1D-4760-8062-CFEA989914FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CB025E4C-ED1D-4760-8062-CFEA989914FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CB025E4C-ED1D-4760-8062-CFEA989914FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CB025E4C-ED1D-4760-8062-CFEA989914FA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{65EB1B23-8CFB-445A-A9A4-C139B09F372F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{65EB1B23-8CFB-445A-A9A4-C139B09F372F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{65EB1B23-8CFB-445A-A9A4-C139B09F372F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{65EB1B23-8CFB-445A-A9A4-C139B09F372F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04}.Release|Any CPU.Build.0 = Release|Any CPU
+		{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3394C204-52AE-4E13-AB87-8BEDC75CEDD0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3394C204-52AE-4E13-AB87-8BEDC75CEDD0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3394C204-52AE-4E13-AB87-8BEDC75CEDD0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3394C204-52AE-4E13-AB87-8BEDC75CEDD0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{84182669-486C-43A1-B05B-7BB0CCBC4E6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{84182669-486C-43A1-B05B-7BB0CCBC4E6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{84182669-486C-43A1-B05B-7BB0CCBC4E6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{84182669-486C-43A1-B05B-7BB0CCBC4E6C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F264C02C-30E7-49B8-9E86-5B2969243109}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F264C02C-30E7-49B8-9E86-5B2969243109}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F264C02C-30E7-49B8-9E86-5B2969243109}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F264C02C-30E7-49B8-9E86-5B2969243109}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3ABC8F86-F0E0-4237-91C3-1F268D266701}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3ABC8F86-F0E0-4237-91C3-1F268D266701}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3ABC8F86-F0E0-4237-91C3-1F268D266701}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3ABC8F86-F0E0-4237-91C3-1F268D266701}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5A19A062-FACD-423D-9D83-A48A836F2568}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5A19A062-FACD-423D-9D83-A48A836F2568}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5A19A062-FACD-423D-9D83-A48A836F2568}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5A19A062-FACD-423D-9D83-A48A836F2568}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D04B70F8-E958-42D2-A3F5-B6E359CD1990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D04B70F8-E958-42D2-A3F5-B6E359CD1990}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D04B70F8-E958-42D2-A3F5-B6E359CD1990}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D04B70F8-E958-42D2-A3F5-B6E359CD1990}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B8327FD5-E268-4A6E-9092-CE57E4966F08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B8327FD5-E268-4A6E-9092-CE57E4966F08}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B8327FD5-E268-4A6E-9092-CE57E4966F08}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B8327FD5-E268-4A6E-9092-CE57E4966F08}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5A32459A-FE82-44D6-BE6C-98421FADBBEF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5A32459A-FE82-44D6-BE6C-98421FADBBEF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5A32459A-FE82-44D6-BE6C-98421FADBBEF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5A32459A-FE82-44D6-BE6C-98421FADBBEF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{98A5AA60-E695-449D-A468-9835F3476A98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{98A5AA60-E695-449D-A468-9835F3476A98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{98A5AA60-E695-449D-A468-9835F3476A98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{98A5AA60-E695-449D-A468-9835F3476A98}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3309FA13-B45B-4A31-B517-C9B54F9B5D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3309FA13-B45B-4A31-B517-C9B54F9B5D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3309FA13-B45B-4A31-B517-C9B54F9B5D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3309FA13-B45B-4A31-B517-C9B54F9B5D5F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9A1B9520-6C5E-4096-9C12-EBA26130DB6F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9A1B9520-6C5E-4096-9C12-EBA26130DB6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9A1B9520-6C5E-4096-9C12-EBA26130DB6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9A1B9520-6C5E-4096-9C12-EBA26130DB6F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{882F9ADC-1317-4DFD-82E6-20DD9E596D6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{882F9ADC-1317-4DFD-82E6-20DD9E596D6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{882F9ADC-1317-4DFD-82E6-20DD9E596D6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{882F9ADC-1317-4DFD-82E6-20DD9E596D6A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE9614E9-C32D-4D55-A956-E8B965938AFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE9614E9-C32D-4D55-A956-E8B965938AFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE9614E9-C32D-4D55-A956-E8B965938AFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE9614E9-C32D-4D55-A956-E8B965938AFE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FF144E37-C3F7-4568-8C8C-BE63EDC78358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FF144E37-C3F7-4568-8C8C-BE63EDC78358}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FF144E37-C3F7-4568-8C8C-BE63EDC78358}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FF144E37-C3F7-4568-8C8C-BE63EDC78358}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8C4EDF99-9492-4768-B8F5-B3915D876DF9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8C4EDF99-9492-4768-B8F5-B3915D876DF9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8C4EDF99-9492-4768-B8F5-B3915D876DF9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8C4EDF99-9492-4768-B8F5-B3915D876DF9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7B18CDC9-66AD-469A-B847-1B38C57F4647}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7B18CDC9-66AD-469A-B847-1B38C57F4647}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7B18CDC9-66AD-469A-B847-1B38C57F4647}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7B18CDC9-66AD-469A-B847-1B38C57F4647}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CBF8AC86-406C-49E5-9261-1A73EACDFF70}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CBF8AC86-406C-49E5-9261-1A73EACDFF70}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CBF8AC86-406C-49E5-9261-1A73EACDFF70}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CBF8AC86-406C-49E5-9261-1A73EACDFF70}.Release|Any CPU.Build.0 = Release|Any CPU
+		{241A462E-9EF2-4AC4-8079-8BF71FE851A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{241A462E-9EF2-4AC4-8079-8BF71FE851A4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{241A462E-9EF2-4AC4-8079-8BF71FE851A4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{241A462E-9EF2-4AC4-8079-8BF71FE851A4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A3E05FEF-78DE-4016-A74E-094EB696B616}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A3E05FEF-78DE-4016-A74E-094EB696B616}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A3E05FEF-78DE-4016-A74E-094EB696B616}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A3E05FEF-78DE-4016-A74E-094EB696B616}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C0501987-3A00-463B-B49E-3AC708B6C4D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C0501987-3A00-463B-B49E-3AC708B6C4D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C0501987-3A00-463B-B49E-3AC708B6C4D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C0501987-3A00-463B-B49E-3AC708B6C4D7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DB17651A-D7F7-4792-B9A8-90D178CCCAE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DB17651A-D7F7-4792-B9A8-90D178CCCAE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DB17651A-D7F7-4792-B9A8-90D178CCCAE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DB17651A-D7F7-4792-B9A8-90D178CCCAE8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6DFB6C23-0F88-41BA-91D3-61DEDF59359F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6DFB6C23-0F88-41BA-91D3-61DEDF59359F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6DFB6C23-0F88-41BA-91D3-61DEDF59359F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6DFB6C23-0F88-41BA-91D3-61DEDF59359F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4016FAEC-445B-421E-B968-B5FD16A23561}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4016FAEC-445B-421E-B968-B5FD16A23561}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4016FAEC-445B-421E-B968-B5FD16A23561}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4016FAEC-445B-421E-B968-B5FD16A23561}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AD6BD65C-78F1-491A-86ED-820C948E6A1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AD6BD65C-78F1-491A-86ED-820C948E6A1D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AD6BD65C-78F1-491A-86ED-820C948E6A1D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AD6BD65C-78F1-491A-86ED-820C948E6A1D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DA3D0490-0B26-4722-86A6-F2659E82021E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DA3D0490-0B26-4722-86A6-F2659E82021E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DA3D0490-0B26-4722-86A6-F2659E82021E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DA3D0490-0B26-4722-86A6-F2659E82021E}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E9C89268-E9B1-4C5C-87C8-E5645E958040}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E9C89268-E9B1-4C5C-87C8-E5645E958040}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E9C89268-E9B1-4C5C-87C8-E5645E958040}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E9C89268-E9B1-4C5C-87C8-E5645E958040}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FB091C23-709B-4D45-87EC-88AED35A4C46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FB091C23-709B-4D45-87EC-88AED35A4C46}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FB091C23-709B-4D45-87EC-88AED35A4C46}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FB091C23-709B-4D45-87EC-88AED35A4C46}.Release|Any CPU.Build.0 = Release|Any CPU
+		{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{4A5926C5-F481-4167-A380-59F1A97535E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{4A5926C5-F481-4167-A380-59F1A97535E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{4A5926C5-F481-4167-A380-59F1A97535E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{4A5926C5-F481-4167-A380-59F1A97535E3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{49BF7A70-7280-421A-B6FC-627A967EAEDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{49BF7A70-7280-421A-B6FC-627A967EAEDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{49BF7A70-7280-421A-B6FC-627A967EAEDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{49BF7A70-7280-421A-B6FC-627A967EAEDD}.Release|Any CPU.Build.0 = Release|Any CPU
+		{95F44A22-1044-4466-A2CF-F1240F57B3F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{95F44A22-1044-4466-A2CF-F1240F57B3F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{95F44A22-1044-4466-A2CF-F1240F57B3F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{95F44A22-1044-4466-A2CF-F1240F57B3F7}.Release|Any CPU.Build.0 = Release|Any CPU
+		{321F9E9B-8819-4125-BC09-B01B3443BE7A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{321F9E9B-8819-4125-BC09-B01B3443BE7A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{321F9E9B-8819-4125-BC09-B01B3443BE7A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{321F9E9B-8819-4125-BC09-B01B3443BE7A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{77B57863-479B-4D86-A579-26C865FC0FE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{77B57863-479B-4D86-A579-26C865FC0FE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{77B57863-479B-4D86-A579-26C865FC0FE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{77B57863-479B-4D86-A579-26C865FC0FE0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8767C756-B325-46FF-B071-8F7DEFF08094}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8767C756-B325-46FF-B071-8F7DEFF08094}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8767C756-B325-46FF-B071-8F7DEFF08094}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8767C756-B325-46FF-B071-8F7DEFF08094}.Release|Any CPU.Build.0 = Release|Any CPU
+		{5F349082-1993-4BEB-A1D3-473B96776DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{5F349082-1993-4BEB-A1D3-473B96776DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{5F349082-1993-4BEB-A1D3-473B96776DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{5F349082-1993-4BEB-A1D3-473B96776DC5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637}.Release|Any CPU.Build.0 = Release|Any CPU
+		{06820024-0B20-402C-BF9C-EFEC04325C98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{06820024-0B20-402C-BF9C-EFEC04325C98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{06820024-0B20-402C-BF9C-EFEC04325C98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{06820024-0B20-402C-BF9C-EFEC04325C98}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9B09E998-546C-47A3-9ED9-67309AE32945}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9B09E998-546C-47A3-9ED9-67309AE32945}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9B09E998-546C-47A3-9ED9-67309AE32945}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9B09E998-546C-47A3-9ED9-67309AE32945}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DF2DAE3E-E816-48B9-B485-AB023A79622B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DF2DAE3E-E816-48B9-B485-AB023A79622B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DF2DAE3E-E816-48B9-B485-AB023A79622B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DF2DAE3E-E816-48B9-B485-AB023A79622B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{BEEC53E9-6E35-42B7-893A-425A1A9034FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{BEEC53E9-6E35-42B7-893A-425A1A9034FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{BEEC53E9-6E35-42B7-893A-425A1A9034FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{BEEC53E9-6E35-42B7-893A-425A1A9034FB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B99E8C6E-2058-4103-B4FA-44FF4003D0EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B99E8C6E-2058-4103-B4FA-44FF4003D0EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B99E8C6E-2058-4103-B4FA-44FF4003D0EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B99E8C6E-2058-4103-B4FA-44FF4003D0EA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{97FB9236-C06B-4000-BAB6-5BC649AA3F3D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{97FB9236-C06B-4000-BAB6-5BC649AA3F3D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{97FB9236-C06B-4000-BAB6-5BC649AA3F3D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{97FB9236-C06B-4000-BAB6-5BC649AA3F3D}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D49117D4-43C3-49FF-8DAB-4446543233F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D49117D4-43C3-49FF-8DAB-4446543233F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D49117D4-43C3-49FF-8DAB-4446543233F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D49117D4-43C3-49FF-8DAB-4446543233F4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{63298041-B1A6-4F17-BC1B-F1182BC3D544}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{63298041-B1A6-4F17-BC1B-F1182BC3D544}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{63298041-B1A6-4F17-BC1B-F1182BC3D544}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{63298041-B1A6-4F17-BC1B-F1182BC3D544}.Release|Any CPU.Build.0 = Release|Any CPU
+		{884100F6-FF7A-4317-85D9-DE99569422BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{884100F6-FF7A-4317-85D9-DE99569422BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{884100F6-FF7A-4317-85D9-DE99569422BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{884100F6-FF7A-4317-85D9-DE99569422BF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5}.Release|Any CPU.Build.0 = Release|Any CPU
+		{3AC218EB-EFD5-42B3-9828-38E46307170A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{3AC218EB-EFD5-42B3-9828-38E46307170A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{3AC218EB-EFD5-42B3-9828-38E46307170A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{3AC218EB-EFD5-42B3-9828-38E46307170A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{E336ACFA-EAB1-475B-AD47-1CD6655D43A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{E336ACFA-EAB1-475B-AD47-1CD6655D43A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{E336ACFA-EAB1-475B-AD47-1CD6655D43A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{E336ACFA-EAB1-475B-AD47-1CD6655D43A3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{91E9585D-0547-4246-952E-4E7592510655}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{91E9585D-0547-4246-952E-4E7592510655}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{91E9585D-0547-4246-952E-4E7592510655}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{91E9585D-0547-4246-952E-4E7592510655}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CE8948EE-C87D-46AD-B643-30C5CA86F107}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CE8948EE-C87D-46AD-B643-30C5CA86F107}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CE8948EE-C87D-46AD-B643-30C5CA86F107}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CE8948EE-C87D-46AD-B643-30C5CA86F107}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8D0CA149-75ED-4BC0-9AF4-784367BC063B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8D0CA149-75ED-4BC0-9AF4-784367BC063B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8D0CA149-75ED-4BC0-9AF4-784367BC063B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8D0CA149-75ED-4BC0-9AF4-784367BC063B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1AB54B73-21AF-412F-B5C5-076C39D0C901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1AB54B73-21AF-412F-B5C5-076C39D0C901}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1AB54B73-21AF-412F-B5C5-076C39D0C901}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1AB54B73-21AF-412F-B5C5-076C39D0C901}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CDCA2085-1915-4AF1-853A-E1B8A88CAABA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CDCA2085-1915-4AF1-853A-E1B8A88CAABA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CDCA2085-1915-4AF1-853A-E1B8A88CAABA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CDCA2085-1915-4AF1-853A-E1B8A88CAABA}.Release|Any CPU.Build.0 = Release|Any CPU
+		{41C422F6-49CA-4EC5-86CB-78D6720FC822}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{41C422F6-49CA-4EC5-86CB-78D6720FC822}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{41C422F6-49CA-4EC5-86CB-78D6720FC822}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{41C422F6-49CA-4EC5-86CB-78D6720FC822}.Release|Any CPU.Build.0 = Release|Any CPU
+		{FCB566EA-EDF0-4D97-8436-C101F384EB76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{FCB566EA-EDF0-4D97-8436-C101F384EB76}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{FCB566EA-EDF0-4D97-8436-C101F384EB76}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{FCB566EA-EDF0-4D97-8436-C101F384EB76}.Release|Any CPU.Build.0 = Release|Any CPU
+		{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{DBDE9159-2423-4473-9853-4101095D93A2} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{DFEFB3E9-95FB-4D29-9A95-68608B1F3AE8} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{758FC429-A223-439E-B4C4-3FC5E318468C} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{F185E45E-9806-4617-BF97-635FCEB61680} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{0F17DA54-D7DA-4EBC-8A4A-63D6ACA43A1D} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{331F0F1E-6A35-4E22-BBFA-004A1D4EE757} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{1B613B04-C002-48F8-B320-EA7BCC8483A7} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{BA955D45-C36D-4CDC-A0BA-708432C63B3E} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{1C829A36-C841-4BD6-993D-1F6EA3998B12} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{AF9F84FA-7B8E-4B6A-AD7F-3BF1579F3AFD} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{D8B7C7FD-5A31-4D8E-82AB-9D0C97BBEBDB} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{DB21BFB8-0FCC-4F17-9773-8141B0B4F0D2} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{D1F4D5E0-D4BB-4FED-AFA9-0DDACA1F5A71} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{E55BB790-87EC-4C8E-9908-8D0C01E5C215} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{E3D46015-AB12-47AB-AB37-5FFF5B781BD9} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{62F13963-52BC-4513-B2F5-ED5E07146860} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{17A5BDBE-C1D1-452E-8627-CE492B3E56BE} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{0CD65A26-E3AC-4D84-9603-4F6E4FA20E20} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{C4AE5AC9-45E3-43A8-93CF-A7B0853FEA4A} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{9557D34F-A76C-4A04-92F6-7769676C60B1} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{5FDE6E83-C44B-46E1-9453-98A2EF4C52C8} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{22D6F789-FE96-48DB-ACC1-3A52664B9F9E} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{F72896F4-43E6-4FBC-8D7D-D0306657DE34} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{B512C62C-677E-4A07-8B96-E973005501E6} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{3B766FF7-0B73-409C-AC9F-833FA152BD0C} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{FB29A674-B8AC-4A1E-9D64-6DC151E7884E} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{842EF7A8-F305-42BC-8740-9ABB58202606} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{BD7B6827-75A9-4DEE-BF71-3379AD78FA3E} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{FADC30C7-4F6D-4C4B-B0C5-53F3424878D5} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{F67A2623-4C33-46D4-9CE3-827C59240089} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{86830781-83E7-40D4-AC04-9F8CB730C5CF} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{19ED9FC4-D6AA-44C6-8B0C-C4B58FFF75AB} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{42F380C0-9B44-40FD-8F15-19D949CCB2BD} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{85B57E4B-C0CC-45A2-BA93-A10302AC9080} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{F85A785C-195A-4B88-9563-6AFED7D8A398} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{FC58281F-374A-4C48-B00E-BB46D6EE2B89} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{48E8B6EF-A590-417C-B7B9-A6345FCD70A0} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{D9D540F8-AEAA-4076-A5A5-5711FC451D99} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{7F321163-AD3F-4F08-83B9-714BDA5FE088} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{3329B3ED-C681-4BA4-9947-5F152A38FD0D} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{5D0FF2A0-BE05-4F07-BB41-8E4A7D0D4442} = {3303F74B-62AC-47B7-A8AA-F93A52A1C95C}
+		{684FA1FC-5BA3-4089-B6C4-5E6797D463C2} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{863F435B-B7C7-4CC8-9A4F-2267385B8487} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{FBDEECDC-AF92-42B3-AE69-3AF91F26F683} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{BE366E7A-F7C8-4AB2-9928-04FC68238883} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A405FB21-249D-4F71-A46E-D943021BA33F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{54EBB5D5-B14C-4297-945E-1A3C11B51740} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A6CE175A-285A-40C1-ABA8-90A9E483FB70} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{3B0DA602-0415-408E-A3AC-84B3EC23DE13} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{EB3333ED-3B41-4C2A-A979-C224E4B7C646} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{E6ACD7AB-2E78-4789-855A-F473E8BEAC6B} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B51D51B6-07C4-4A8D-AA08-7BAE69548ED8} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{252C4A30-8AB3-4A5C-AA06-21D49D9E2AA4} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{1FD342FB-67C0-4A93-8DCE-93180CAF38A2} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{F74F4279-B424-49A9-A539-909FD5298A04} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{5A24CA2C-7E8F-4123-9B2C-9866957A76B9} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B9285667-4EBE-4EF7-AB66-396F8651BDAD} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{97E48A24-B5CB-478E-AF2A-B8FB2350DB12} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{AC08CDB7-CA75-4A66-AD41-DAB86D6C8435} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B4F23CFF-7434-4FC9-AD7E-B25012D6AB69} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{CB9E0567-82A1-4E03-95B9-8397A80A7144} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{21BF1A27-D8A6-4C6C-9C2E-9E3C798F25A1} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{EC4A3AD2-1923-4816-904F-B49A9B1D1ECB} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{7628BE7F-AD0D-4C08-95FF-907E78593169} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{21C347CC-D097-4B78-8B2D-9763B3FA868E} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{78FBF12B-FF17-4FAB-A51C-375DFB376A84} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{6E91AA59-BD05-49EC-8DEA-C69542C8438F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A680BF33-6C6E-4093-84C1-813C51BDA1E7} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{4BC37EC1-225E-4949-AAE0-44E3DCE0E141} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{4E1525D6-8F38-4599-BA08-C1A3E4BAF50D} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{C43D0602-7C1C-46BA-B4C4-FBC1C1428859} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{BF12CAF7-F9F8-4B6B-AC94-2EFE2345AAF6} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{1D0DEF05-4CBE-4738-AAF0-CC5DEDBE9833} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{53713CF1-576B-480A-B40A-1753A4A90CC3} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{EF104B33-8F43-458A-9533-597CF8389004} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{BCB6248A-D3A4-4BC5-AF3C-35BAB88009E6} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{802FAF1C-3A5E-44D9-8D0A-ED292579CF00} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{E582C914-C7B0-4812-92DE-7849F485EAD4} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{FFE3F9EB-D6F9-47EE-AA5F-486053610D80} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A901A7DB-5CAC-4245-9920-6BC28DCC94D8} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{0DA78D58-5ABC-4C33-B390-A3022E815B36} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{89D0A49C-D534-4DE0-8357-75F8AE363994} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A340652C-93D8-42AB-8724-08A0BC737A05} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{58B4C338-F610-4227-8685-DD04393587A0} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{338D09E0-2EEF-4C00-B360-77EDCDEDC3C9} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{672CEA36-D471-4ECA-9FB4-CE4576835A28} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DE1B6A83-3B0D-418C-B5AC-FB0BAD2A2D0A} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{37A064B1-AB4D-4137-B912-B6D358407A26} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DA9C49FF-6215-406D-BD5E-2EA3F8BFE0DB} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{D0D3DDF6-5338-4751-BA6E-8D64A77201B9} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{16711F82-EB7C-4D74-9E4E-ECB8B20BA1ED} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{E2A8FC3A-9154-4DBC-BF66-FEF6D11DF3E8} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{23101060-4031-4158-92F2-0E4995C24ADE} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{9D5AF8C8-791B-47F1-986D-27900531B594} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{EE8DC120-142D-40EE-A846-2BB56BEA4608} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{6F459E05-765F-4DBA-82E3-EAD6A4B2874C} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{D06A3406-D4CF-4317-BEB6-A631CB3F51DC} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B037C0BA-CE27-4C1D-A869-65FF4C4A5689} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{CB025E4C-ED1D-4760-8062-CFEA989914FA} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{65EB1B23-8CFB-445A-A9A4-C139B09F372F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{4AECB0DD-B4F2-4A00-AAC6-F416EAC44C04} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{97EF0A86-F251-4FA5-8DAA-DC6C1921E1A3} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{3394C204-52AE-4E13-AB87-8BEDC75CEDD0} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{2F966CBF-1BE3-4F07-823E-5CC5DDB1D71F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{84182669-486C-43A1-B05B-7BB0CCBC4E6C} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{F264C02C-30E7-49B8-9E86-5B2969243109} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{3ABC8F86-F0E0-4237-91C3-1F268D266701} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{5A19A062-FACD-423D-9D83-A48A836F2568} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{D04B70F8-E958-42D2-A3F5-B6E359CD1990} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B8327FD5-E268-4A6E-9092-CE57E4966F08} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{5A32459A-FE82-44D6-BE6C-98421FADBBEF} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A9F9A76D-EA0E-4AD1-98CC-95DB4BE0E0DD} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{98A5AA60-E695-449D-A468-9835F3476A98} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{F23D07E8-8AA1-4B71-BDAC-F4233E9C2B97} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{3309FA13-B45B-4A31-B517-C9B54F9B5D5F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{1328C1EA-6B69-4EE7-A1B9-9C83B83F3988} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{9A1B9520-6C5E-4096-9C12-EBA26130DB6F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{882F9ADC-1317-4DFD-82E6-20DD9E596D6A} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{AE9614E9-C32D-4D55-A956-E8B965938AFE} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{FF144E37-C3F7-4568-8C8C-BE63EDC78358} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{8C4EDF99-9492-4768-B8F5-B3915D876DF9} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{7B18CDC9-66AD-469A-B847-1B38C57F4647} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{CBF8AC86-406C-49E5-9261-1A73EACDFF70} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{241A462E-9EF2-4AC4-8079-8BF71FE851A4} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{8942C4D3-42D1-4A35-A98F-DF2C3F8E5318} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{A3E05FEF-78DE-4016-A74E-094EB696B616} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{C0501987-3A00-463B-B49E-3AC708B6C4D7} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{F6F5FC24-C5A6-4C54-AE21-F814CA7D4895} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DB17651A-D7F7-4792-B9A8-90D178CCCAE8} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{6DFB6C23-0F88-41BA-91D3-61DEDF59359F} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{4016FAEC-445B-421E-B968-B5FD16A23561} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{AD6BD65C-78F1-491A-86ED-820C948E6A1D} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DA3D0490-0B26-4722-86A6-F2659E82021E} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{E9C89268-E9B1-4C5C-87C8-E5645E958040} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{FB091C23-709B-4D45-87EC-88AED35A4C46} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{21BE5954-386A-4A9D-A5E2-9E5E934A3BCA} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{4A5926C5-F481-4167-A380-59F1A97535E3} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{49BF7A70-7280-421A-B6FC-627A967EAEDD} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{95F44A22-1044-4466-A2CF-F1240F57B3F7} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{321F9E9B-8819-4125-BC09-B01B3443BE7A} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{7B74F0E7-C0D8-46E3-B6AB-7BBBFCA5A29C} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{77B57863-479B-4D86-A579-26C865FC0FE0} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{8767C756-B325-46FF-B071-8F7DEFF08094} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{5F349082-1993-4BEB-A1D3-473B96776DC5} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B91AFD2E-0C36-4BE9-A252-FFD4A2EF3C8C} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{6C52BF11-3EB7-4DF6-8B5C-17711BA60A28} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B7D7FBCB-615A-4553-AA7B-CA6B5DFE5637} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{06820024-0B20-402C-BF9C-EFEC04325C98} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{9B09E998-546C-47A3-9ED9-67309AE32945} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DF2DAE3E-E816-48B9-B485-AB023A79622B} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{BEEC53E9-6E35-42B7-893A-425A1A9034FB} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{B99E8C6E-2058-4103-B4FA-44FF4003D0EA} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{97FB9236-C06B-4000-BAB6-5BC649AA3F3D} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{D49117D4-43C3-49FF-8DAB-4446543233F4} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{63298041-B1A6-4F17-BC1B-F1182BC3D544} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{884100F6-FF7A-4317-85D9-DE99569422BF} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{DD0851A5-CAEB-4564-B69E-4E29ED7E49E5} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{3AC218EB-EFD5-42B3-9828-38E46307170A} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{E336ACFA-EAB1-475B-AD47-1CD6655D43A3} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{91E9585D-0547-4246-952E-4E7592510655} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{CE8948EE-C87D-46AD-B643-30C5CA86F107} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{8D0CA149-75ED-4BC0-9AF4-784367BC063B} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{1AB54B73-21AF-412F-B5C5-076C39D0C901} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{CDCA2085-1915-4AF1-853A-E1B8A88CAABA} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{41C422F6-49CA-4EC5-86CB-78D6720FC822} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{FCB566EA-EDF0-4D97-8436-C101F384EB76} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
+		{82C5DF7B-6F86-40D3-8F65-4B63D41E23A5} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
 	EndGlobalSection
 EndGlobal
diff --git a/test.ps1 b/test.ps1
index d54795e636..050fb9c7d7 100644
--- a/test.ps1
+++ b/test.ps1
@@ -26,7 +26,9 @@ param (
 . ./shared.ps1
 
 $buildDir = Join-Path $PSScriptRoot "build"
-$exercisesDir = Resolve-Path "exercises"
+$practiceExercisesDir = Join-Path $buildDir "practice"
+$conceptExercisesDir = Join-Path $buildDir "concept"
+$sourceDir = Resolve-Path "exercises"
 
 function Configlet-Lint {
     Write-Output "Linting config.json"
@@ -46,7 +48,7 @@ function Clean {
 
 function Copy-Exercises {
     Write-Output "Copying exercises"
-    Copy-Item $exercisesDir -Destination $buildDir -Recurse
+    Copy-Item $sourceDir -Destination $buildDir -Recurse
 }
 
 function Enable-All-Tests {
@@ -58,12 +60,20 @@ function Enable-All-Tests {
 
 function Test-Refactoring-Projects {
     Write-Output "Testing refactoring projects"
-    @("tree-building", "ledger", "markdown") | ForEach-Object { Run-Command "dotnet test $buildDir/$_" }
+    @("tree-building", "ledger", "markdown") | ForEach-Object { Run-Command "dotnet test $practiceExercisesDir/$_" }
 }
 
-function Replace-Stubs-With-Example {
-    Write-Output "Replacing stubs with example"
-    Get-ChildItem -Path $buildDir -Include "*.csproj" -Recurse | ForEach-Object {
+function Replace-Stubs {
+    Write-Output "Replacing concept exercise stubs with exemplar"
+    Get-ChildItem -Path $conceptExercisesDir -Include "*.csproj" -Recurse | ForEach-Object {
+        $stub = Join-Path $_.Directory ($_.BaseName + ".cs")
+        $example = Join-Path $_.Directory ".meta" "Exemplar.cs"
+    
+        Move-Item -Path $example -Destination $stub -Force
+    }
+
+    Write-Output "Replacing practice exercise stubs with example"
+    Get-ChildItem -Path $practiceExercisesDir -Include "*.csproj" -Recurse | ForEach-Object {
         $stub = Join-Path $_.Directory ($_.BaseName + ".cs")
         $example = Join-Path $_.Directory "Example.cs"
     
@@ -73,8 +83,19 @@ function Replace-Stubs-With-Example {
 
 function Test-Using-Example-Implementation {
     Write-Output "Running tests"
-    $testTarget = if ($Exercise) { "$buildDir/$Exercise" } else { "$buildDir/Exercises.sln" }
-    Run-Command "dotnet test $testTarget"
+
+    if (-Not $Exercise) {
+        Run-Command "dotnet test $buildDir/Exercises.sln"
+    }
+    elseif (Test-Path "$conceptExercisesDir/$exercise") {
+        Run-Command "dotnet test $conceptExercisesDir/$exercise"
+    }
+    elseif (Test-Path "$practiceExercisesDir/$exercise") {
+        Run-Command "dotnet test $practiceExercisesDir/$exercise"
+    }
+    else {
+        throw "Could not find exercise '$exercise'"
+    }
 }
 
 Configlet-Lint
@@ -87,7 +108,7 @@ if (!$Exercise) {
     Test-Refactoring-Projects
 }
 
-Replace-Stubs-With-Example
+Replace-Stubs
 Test-Using-Example-Implementation
 
 exit $LastExitCode
\ No newline at end of file

From 5ace391f907c7d81efe1cbfccfb3ad44b5eab2fa Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 9 Feb 2021 12:23:20 +0100
Subject: [PATCH 326/327] [v3] Add level one headings to Markdown files.

All Markdown files should, from this point on, start with a level one heading.
See https://github.com/exercism/configlet/issues/150 for the rationale behind these changes.

The full specification can be found [here](https://github.com/exercism/docs/blob/main/contributing/standards/markdown.md).
---
 concepts/arrays/about.md                                        | 2 ++
 concepts/arrays/introduction.md                                 | 2 ++
 concepts/attributes/about.md                                    | 2 ++
 concepts/attributes/introduction.md                             | 2 ++
 concepts/basics/about.md                                        | 2 ++
 concepts/basics/introduction.md                                 | 2 ++
 concepts/bit-manipulation/about.md                              | 2 ++
 concepts/bit-manipulation/introduction.md                       | 2 ++
 concepts/booleans/about.md                                      | 2 ++
 concepts/booleans/introduction.md                               | 2 ++
 concepts/casting/about.md                                       | 2 ++
 concepts/casting/introduction.md                                | 2 ++
 concepts/chars/about.md                                         | 2 ++
 concepts/chars/introduction.md                                  | 2 ++
 concepts/classes/about.md                                       | 2 ++
 concepts/classes/introduction.md                                | 2 ++
 concepts/compound-assignment/about.md                           | 2 ++
 concepts/compound-assignment/introduction.md                    | 2 ++
 concepts/const-readonly/about.md                                | 2 ++
 concepts/const-readonly/introduction.md                         | 2 ++
 concepts/constants/about.md                                     | 2 ++
 concepts/constants/introduction.md                              | 2 ++
 concepts/constructors/about.md                                  | 2 ++
 concepts/constructors/introduction.md                           | 2 ++
 concepts/datetimes/about.md                                     | 2 ++
 concepts/datetimes/introduction.md                              | 2 ++
 concepts/defensive-copying/about.md                             | 2 ++
 concepts/defensive-copying/introduction.md                      | 2 ++
 concepts/dictionaries/about.md                                  | 2 ++
 concepts/dictionaries/introduction.md                           | 2 ++
 concepts/do-while-loops/about.md                                | 2 ++
 concepts/do-while-loops/introduction.md                         | 2 ++
 concepts/enums/about.md                                         | 2 ++
 concepts/enums/introduction.md                                  | 2 ++
 concepts/equality/about.md                                      | 2 ++
 concepts/equality/introduction.md                               | 2 ++
 concepts/exception-filtering/about.md                           | 2 ++
 concepts/exception-filtering/introduction.md                    | 2 ++
 concepts/exceptions/about.md                                    | 2 ++
 concepts/exceptions/introduction.md                             | 2 ++
 concepts/explicit-casts/about.md                                | 2 ++
 concepts/explicit-casts/introduction.md                         | 2 ++
 concepts/expression-bodied-members/about.md                     | 2 ++
 concepts/expression-bodied-members/introduction.md              | 2 ++
 concepts/flag-enums/about.md                                    | 2 ++
 concepts/flag-enums/introduction.md                             | 2 ++
 concepts/floating-point-numbers/about.md                        | 2 ++
 concepts/floating-point-numbers/introduction.md                 | 2 ++
 concepts/for-loops/about.md                                     | 2 ++
 concepts/for-loops/introduction.md                              | 2 ++
 concepts/foreach-loops/about.md                                 | 2 ++
 concepts/foreach-loops/introduction.md                          | 2 ++
 concepts/generic-types/about.md                                 | 2 ++
 concepts/generic-types/introduction.md                          | 2 ++
 concepts/if-statements/about.md                                 | 2 ++
 concepts/if-statements/introduction.md                          | 2 ++
 concepts/indexers/about.md                                      | 2 ++
 concepts/indexers/introduction.md                               | 2 ++
 concepts/inheritance/about.md                                   | 2 ++
 concepts/inheritance/introduction.md                            | 2 ++
 concepts/integral-numbers/about.md                              | 2 ++
 concepts/integral-numbers/introduction.md                       | 2 ++
 concepts/interfaces/about.md                                    | 2 ++
 concepts/interfaces/introduction.md                             | 2 ++
 concepts/lists/about.md                                         | 2 ++
 concepts/lists/introduction.md                                  | 2 ++
 concepts/memory-allocation/about.md                             | 2 ++
 concepts/memory-allocation/introduction.md                      | 2 ++
 concepts/method-overloading/about.md                            | 2 ++
 concepts/method-overloading/introduction.md                     | 2 ++
 concepts/named-arguments/about.md                               | 2 ++
 concepts/named-arguments/introduction.md                        | 2 ++
 concepts/namespaces/about.md                                    | 2 ++
 concepts/namespaces/introduction.md                             | 2 ++
 concepts/nested-types/about.md                                  | 2 ++
 concepts/nested-types/introduction.md                           | 2 ++
 concepts/nullability/about.md                                   | 2 ++
 concepts/nullability/introduction.md                            | 2 ++
 concepts/numbers/about.md                                       | 2 ++
 concepts/numbers/introduction.md                                | 2 ++
 concepts/object-initializers/about.md                           | 2 ++
 concepts/object-initializers/introduction.md                    | 2 ++
 concepts/operator-overloading/about.md                          | 2 ++
 concepts/operator-overloading/introduction.md                   | 2 ++
 concepts/optional-parameters/about.md                           | 2 ++
 concepts/optional-parameters/introduction.md                    | 2 ++
 concepts/ordering/about.md                                      | 2 ++
 concepts/ordering/introduction.md                               | 2 ++
 concepts/overflow/about.md                                      | 2 ++
 concepts/overflow/introduction.md                               | 2 ++
 concepts/parameters/about.md                                    | 2 ++
 concepts/parameters/introduction.md                             | 2 ++
 concepts/properties/about.md                                    | 2 ++
 concepts/properties/introduction.md                             | 2 ++
 concepts/randomness/about.md                                    | 2 ++
 concepts/randomness/introduction.md                             | 2 ++
 concepts/readonly-collections/about.md                          | 2 ++
 concepts/readonly-collections/introduction.md                   | 2 ++
 concepts/regular-expressions/about.md                           | 2 ++
 concepts/regular-expressions/introduction.md                    | 2 ++
 concepts/resource-cleanup/about.md                              | 2 ++
 concepts/resource-cleanup/introduction.md                       | 2 ++
 concepts/resource-lifetime/about.md                             | 2 ++
 concepts/resource-lifetime/introduction.md                      | 2 ++
 concepts/sets/about.md                                          | 2 ++
 concepts/sets/introduction.md                                   | 2 ++
 concepts/string-builder/about.md                                | 2 ++
 concepts/string-builder/introduction.md                         | 2 ++
 concepts/string-formatting/about.md                             | 2 ++
 concepts/string-formatting/introduction.md                      | 2 ++
 concepts/string-interpolation/about.md                          | 2 ++
 concepts/string-interpolation/introduction.md                   | 2 ++
 concepts/strings/about.md                                       | 2 ++
 concepts/strings/introduction.md                                | 2 ++
 concepts/structs/about.md                                       | 2 ++
 concepts/structs/introduction.md                                | 2 ++
 concepts/switch-expressions/about.md                            | 2 ++
 concepts/switch-expressions/introduction.md                     | 2 ++
 concepts/switch-statements/about.md                             | 2 ++
 concepts/switch-statements/introduction.md                      | 2 ++
 concepts/ternary-operators/about.md                             | 2 ++
 concepts/ternary-operators/introduction.md                      | 2 ++
 concepts/throw-expressions/about.md                             | 2 ++
 concepts/throw-expressions/introduction.md                      | 2 ++
 concepts/time/about.md                                          | 2 ++
 concepts/time/introduction.md                                   | 2 ++
 concepts/timezone/about.md                                      | 2 ++
 concepts/timezone/introduction.md                               | 2 ++
 concepts/tuples/about.md                                        | 2 ++
 concepts/tuples/introduction.md                                 | 2 ++
 concepts/user-defined-exceptions/about.md                       | 2 ++
 concepts/user-defined-exceptions/introduction.md                | 2 ++
 concepts/varargs/about.md                                       | 2 ++
 concepts/varargs/introduction.md                                | 2 ++
 concepts/verbatim-strings/about.md                              | 2 ++
 concepts/verbatim-strings/introduction.md                       | 2 ++
 concepts/while-loops/about.md                                   | 2 ++
 concepts/while-loops/introduction.md                            | 2 ++
 docs/ABOUT.md                                                   | 2 ++
 docs/INSTALLATION.md                                            | 2 ++
 docs/LEARNING.md                                                | 2 +-
 docs/RESOURCES.md                                               | 2 +-
 docs/TESTS.md                                                   | 2 ++
 exercises/concept/annalyns-infiltration/.docs/hints.md          | 2 ++
 exercises/concept/annalyns-infiltration/.docs/instructions.md   | 2 ++
 exercises/concept/annalyns-infiltration/.docs/introduction.md   | 2 ++
 exercises/concept/annalyns-infiltration/.meta/design.md         | 2 ++
 exercises/concept/attack-of-the-trolls/.docs/hints.md           | 2 ++
 exercises/concept/attack-of-the-trolls/.docs/instructions.md    | 2 ++
 exercises/concept/attack-of-the-trolls/.docs/introduction.md    | 2 ++
 exercises/concept/attack-of-the-trolls/.meta/design.md          | 2 ++
 exercises/concept/authentication-system/.docs/hints.md          | 2 ++
 exercises/concept/authentication-system/.docs/instructions.md   | 2 ++
 exercises/concept/authentication-system/.docs/introduction.md   | 2 ++
 exercises/concept/authentication-system/.meta/design.md         | 2 ++
 exercises/concept/beauty-salon-goes-global/.docs/hints.md       | 2 ++
 .../concept/beauty-salon-goes-global/.docs/instructions.md      | 2 ++
 .../concept/beauty-salon-goes-global/.docs/introduction.md      | 2 ++
 exercises/concept/beauty-salon-goes-global/.meta/design.md      | 2 ++
 exercises/concept/bird-watcher/.docs/hints.md                   | 2 ++
 exercises/concept/bird-watcher/.docs/instructions.md            | 2 ++
 exercises/concept/bird-watcher/.docs/introduction.md            | 2 ++
 exercises/concept/bird-watcher/.meta/design.md                  | 2 ++
 exercises/concept/booking-up-for-beauty/.docs/hints.md          | 2 ++
 exercises/concept/booking-up-for-beauty/.docs/instructions.md   | 2 ++
 exercises/concept/booking-up-for-beauty/.docs/introduction.md   | 2 ++
 exercises/concept/booking-up-for-beauty/.meta/design.md         | 2 ++
 exercises/concept/building-telemetry/.docs/hints.md             | 2 ++
 exercises/concept/building-telemetry/.docs/instructions.md      | 2 ++
 exercises/concept/building-telemetry/.docs/introduction.md      | 2 ++
 exercises/concept/building-telemetry/.meta/design.md            | 2 ++
 exercises/concept/calculator-conundrum/.docs/hints.md           | 2 ++
 exercises/concept/calculator-conundrum/.docs/instructions.md    | 2 ++
 exercises/concept/calculator-conundrum/.docs/introduction.md    | 2 ++
 exercises/concept/calculator-conundrum/.meta/design.md          | 2 ++
 exercises/concept/cars-assemble/.docs/hints.md                  | 2 ++
 exercises/concept/cars-assemble/.docs/instructions.md           | 2 ++
 exercises/concept/cars-assemble/.docs/introduction.md           | 2 ++
 exercises/concept/cars-assemble/.meta/design.md                 | 2 ++
 exercises/concept/developer-privileges/.docs/hints.md           | 2 ++
 exercises/concept/developer-privileges/.docs/instructions.md    | 2 ++
 exercises/concept/developer-privileges/.docs/introduction.md    | 2 ++
 exercises/concept/developer-privileges/.meta/design.md          | 2 ++
 exercises/concept/elons-toys/.docs/hints.md                     | 2 ++
 exercises/concept/elons-toys/.docs/instructions.md              | 2 ++
 exercises/concept/elons-toys/.docs/introduction.md              | 2 ++
 exercises/concept/elons-toys/.meta/design.md                    | 2 ++
 exercises/concept/faceid-2/.docs/hints.md                       | 2 ++
 exercises/concept/faceid-2/.docs/instructions.md                | 2 ++
 exercises/concept/faceid-2/.docs/introduction.md                | 2 ++
 exercises/concept/faceid-2/.meta/design.md                      | 2 ++
 exercises/concept/football-match-reports/.docs/hints.md         | 2 +-
 exercises/concept/football-match-reports/.docs/instructions.md  | 2 ++
 exercises/concept/football-match-reports/.docs/introduction.md  | 2 ++
 exercises/concept/football-match-reports/.meta/design.md        | 2 ++
 exercises/concept/high-school-sweethearts/.docs/hints.md        | 2 ++
 exercises/concept/high-school-sweethearts/.docs/instructions.md | 2 ++
 exercises/concept/high-school-sweethearts/.docs/introduction.md | 2 ++
 exercises/concept/high-school-sweethearts/.meta/design.md       | 2 ++
 exercises/concept/hyper-optimized-telemetry/.docs/hints.md      | 2 ++
 .../concept/hyper-optimized-telemetry/.docs/instructions.md     | 2 ++
 .../concept/hyper-optimized-telemetry/.docs/introduction.md     | 2 ++
 exercises/concept/hyper-optimized-telemetry/.meta/design.md     | 2 ++
 exercises/concept/hyperia-forex/.docs/hints.md                  | 2 ++
 exercises/concept/hyperia-forex/.docs/instructions.md           | 2 ++
 exercises/concept/hyperia-forex/.docs/introduction.md           | 2 ++
 exercises/concept/hyperia-forex/.meta/design.md                 | 2 ++
 exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md    | 2 ++
 .../concept/hyperinflation-hits-hyperia/.docs/instructions.md   | 2 ++
 .../concept/hyperinflation-hits-hyperia/.docs/introduction.md   | 2 ++
 exercises/concept/hyperinflation-hits-hyperia/.meta/design.md   | 2 ++
 exercises/concept/instruments-of-texas/.docs/hints.md           | 2 ++
 exercises/concept/instruments-of-texas/.docs/instructions.md    | 2 ++
 exercises/concept/instruments-of-texas/.docs/introduction.md    | 2 ++
 exercises/concept/instruments-of-texas/.meta/design.md          | 2 ++
 exercises/concept/interest-is-interesting/.docs/hints.md        | 2 ++
 exercises/concept/interest-is-interesting/.docs/instructions.md | 2 ++
 exercises/concept/interest-is-interesting/.docs/introduction.md | 2 ++
 exercises/concept/interest-is-interesting/.meta/design.md       | 2 ++
 .../concept/international-calling-connoisseur/.docs/hints.md    | 2 ++
 .../international-calling-connoisseur/.docs/instructions.md     | 2 ++
 .../international-calling-connoisseur/.docs/introduction.md     | 2 ++
 .../concept/international-calling-connoisseur/.meta/design.md   | 2 ++
 exercises/concept/land-grab-in-space/.docs/hints.md             | 2 ++
 exercises/concept/land-grab-in-space/.docs/instructions.md      | 2 ++
 exercises/concept/land-grab-in-space/.docs/introduction.md      | 2 ++
 exercises/concept/land-grab-in-space/.meta/design.md            | 2 ++
 exercises/concept/log-levels/.docs/hints.md                     | 2 ++
 exercises/concept/log-levels/.docs/instructions.md              | 2 ++
 exercises/concept/log-levels/.docs/introduction.md              | 2 ++
 exercises/concept/log-levels/.meta/design.md                    | 2 ++
 exercises/concept/logs-logs-logs/.docs/hints.md                 | 2 ++
 exercises/concept/logs-logs-logs/.docs/instructions.md          | 2 ++
 exercises/concept/logs-logs-logs/.docs/introduction.md          | 2 ++
 exercises/concept/logs-logs-logs/.meta/design.md                | 2 ++
 exercises/concept/lucians-luscious-lasagna/.docs/hints.md       | 2 ++
 .../concept/lucians-luscious-lasagna/.docs/instructions.md      | 2 ++
 .../concept/lucians-luscious-lasagna/.docs/introduction.md      | 2 ++
 exercises/concept/lucians-luscious-lasagna/.meta/design.md      | 2 ++
 exercises/concept/need-for-speed/.docs/hints.md                 | 2 ++
 exercises/concept/need-for-speed/.docs/instructions.md          | 2 ++
 exercises/concept/need-for-speed/.docs/introduction.md          | 2 ++
 exercises/concept/need-for-speed/.meta/design.md                | 2 ++
 exercises/concept/object-relational-mapping/.docs/hints.md      | 2 ++
 .../concept/object-relational-mapping/.docs/instructions.md     | 2 ++
 .../concept/object-relational-mapping/.docs/introduction.md     | 2 ++
 exercises/concept/object-relational-mapping/.meta/design.md     | 2 ++
 exercises/concept/orm-in-one-go/.docs/hints.md                  | 2 ++
 exercises/concept/orm-in-one-go/.docs/instructions.md           | 2 ++
 exercises/concept/orm-in-one-go/.docs/introduction.md           | 2 ++
 exercises/concept/orm-in-one-go/.meta/design.md                 | 2 ++
 exercises/concept/parsing-log-files/.docs/hints.md              | 2 +-
 exercises/concept/parsing-log-files/.docs/instructions.md       | 2 ++
 exercises/concept/parsing-log-files/.docs/introduction.md       | 2 ++
 exercises/concept/parsing-log-files/.meta/design.md             | 2 ++
 exercises/concept/phone-number-analysis/.docs/hints.md          | 2 ++
 exercises/concept/phone-number-analysis/.docs/instructions.md   | 2 ++
 exercises/concept/phone-number-analysis/.docs/introduction.md   | 2 ++
 exercises/concept/phone-number-analysis/.meta/design.md         | 2 ++
 exercises/concept/red-vs-blue-darwin-style/.docs/hints.md       | 2 ++
 .../concept/red-vs-blue-darwin-style/.docs/instructions.md      | 2 ++
 .../concept/red-vs-blue-darwin-style/.docs/introduction.md      | 2 ++
 exercises/concept/red-vs-blue-darwin-style/.meta/design.md      | 2 ++
 exercises/concept/remote-control-cleanup/.docs/hints.md         | 2 ++
 exercises/concept/remote-control-cleanup/.docs/instructions.md  | 2 ++
 exercises/concept/remote-control-cleanup/.docs/introduction.md  | 2 ++
 exercises/concept/remote-control-cleanup/.meta/design.md        | 2 ++
 exercises/concept/remote-control-competition/.docs/hints.md     | 2 ++
 .../concept/remote-control-competition/.docs/instructions.md    | 2 ++
 .../concept/remote-control-competition/.docs/introduction.md    | 2 ++
 exercises/concept/remote-control-competition/.meta/design.md    | 2 ++
 exercises/concept/roll-the-die/.docs/hints.md                   | 2 ++
 exercises/concept/roll-the-die/.docs/instructions.md            | 2 ++
 exercises/concept/roll-the-die/.docs/introduction.md            | 2 ++
 exercises/concept/roll-the-die/.meta/design.md                  | 2 ++
 exercises/concept/secure-munchester-united/.docs/hints.md       | 2 ++
 .../concept/secure-munchester-united/.docs/instructions.md      | 2 ++
 .../concept/secure-munchester-united/.docs/introduction.md      | 2 ++
 exercises/concept/secure-munchester-united/.meta/design.md      | 2 ++
 exercises/concept/squeaky-clean/.docs/hints.md                  | 2 ++
 exercises/concept/squeaky-clean/.docs/instructions.md           | 2 ++
 exercises/concept/squeaky-clean/.docs/introduction.md           | 2 ++
 exercises/concept/squeaky-clean/.meta/design.md                 | 2 ++
 exercises/concept/the-weather-in-deather/.docs/hints.md         | 2 +-
 exercises/concept/the-weather-in-deather/.docs/instructions.md  | 2 ++
 exercises/concept/the-weather-in-deather/.docs/introduction.md  | 2 ++
 exercises/concept/the-weather-in-deather/.meta/design.md        | 2 ++
 exercises/concept/tim-from-marketing/.docs/hints.md             | 2 ++
 exercises/concept/tim-from-marketing/.docs/instructions.md      | 2 ++
 exercises/concept/tim-from-marketing/.docs/introduction.md      | 2 ++
 exercises/concept/tim-from-marketing/.meta/design.md            | 2 ++
 exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md     | 2 ++
 .../concept/tracks-on-tracks-on-tracks/.docs/instructions.md    | 2 ++
 .../concept/tracks-on-tracks-on-tracks/.docs/introduction.md    | 2 ++
 exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md    | 2 ++
 exercises/concept/weighing-machine/.docs/hints.md               | 2 ++
 exercises/concept/weighing-machine/.docs/instructions.md        | 2 ++
 exercises/concept/weighing-machine/.docs/introduction.md        | 2 ++
 exercises/concept/weighing-machine/.meta/design.md              | 2 ++
 exercises/concept/wizards-and-warriors-2/.docs/hints.md         | 2 ++
 exercises/concept/wizards-and-warriors-2/.docs/instructions.md  | 2 ++
 exercises/concept/wizards-and-warriors-2/.docs/introduction.md  | 2 ++
 exercises/concept/wizards-and-warriors-2/.meta/design.md        | 2 ++
 exercises/concept/wizards-and-warriors/.docs/hints.md           | 2 ++
 exercises/concept/wizards-and-warriors/.docs/instructions.md    | 2 ++
 exercises/concept/wizards-and-warriors/.docs/introduction.md    | 2 ++
 exercises/concept/wizards-and-warriors/.meta/design.md          | 2 ++
 exercises/practice/accumulate/.meta/hints.md                    | 2 ++
 exercises/practice/allergies/.meta/hints.md                     | 2 +-
 exercises/practice/alphametics/.meta/hints.md                   | 2 +-
 exercises/practice/bank-account/.meta/hints.md                  | 2 +-
 exercises/practice/beer-song/.meta/hints.md                     | 2 +-
 exercises/practice/clock/.meta/hints.md                         | 2 +-
 exercises/practice/custom-set/.meta/hints.md                    | 2 +-
 exercises/practice/diamond/.meta/hints.md                       | 2 +-
 exercises/practice/difference-of-squares/.meta/hints.md         | 2 +-
 exercises/practice/diffie-hellman/.meta/hints.md                | 2 +-
 exercises/practice/dot-dsl/.meta/hints.md                       | 2 +-
 exercises/practice/food-chain/.meta/hints.md                    | 2 +-
 exercises/practice/forth/.meta/hints.md                         | 2 +-
 exercises/practice/hangman/.meta/hints.md                       | 2 +-
 exercises/practice/house/.meta/hints.md                         | 2 +-
 exercises/practice/leap/.meta/hints.md                          | 2 +-
 exercises/practice/list-ops/.meta/hints.md                      | 2 +-
 exercises/practice/markdown/.meta/hints.md                      | 2 +-
 exercises/practice/nth-prime/.meta/hints.md                     | 2 +-
 exercises/practice/nucleotide-count/.meta/hints.md              | 2 +-
 exercises/practice/palindrome-products/.meta/hints.md           | 2 +-
 exercises/practice/proverb/.meta/hints.md                       | 2 +-
 exercises/practice/rational-numbers/hints.md                    | 2 +-
 exercises/practice/react/.meta/hints.md                         | 2 +-
 exercises/practice/roman-numerals/.meta/hints.md                | 2 +-
 exercises/practice/saddle-points/.meta/hints.md                 | 2 +-
 exercises/practice/sgf-parsing/.meta/hints.md                   | 2 +-
 exercises/practice/simple-linked-list/.meta/hints.md            | 2 +-
 exercises/practice/sublist/.meta/hints.md                       | 2 +-
 exercises/practice/sum-of-multiples/.meta/hints.md              | 2 +-
 exercises/practice/twelve-days/.meta/hints.md                   | 2 +-
 exercises/practice/variable-length-quantity/.meta/hints.md      | 2 +-
 exercises/practice/word-search/.meta/hints.md                   | 2 +-
 exercises/practice/wordy/.meta/hints.md                         | 2 +-
 exercises/practice/zebra-puzzle/.meta/hints.md                  | 2 +-
 exercises/practice/zipper/.meta/hints.md                        | 2 +-
 reference/exercise-concepts/isbn-verifier.md                    | 2 ++
 344 files changed, 648 insertions(+), 40 deletions(-)

diff --git a/concepts/arrays/about.md b/concepts/arrays/about.md
index b46d9d77d7..d0b115e7aa 100644
--- a/concepts/arrays/about.md
+++ b/concepts/arrays/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts.
 Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
 
diff --git a/concepts/arrays/introduction.md b/concepts/arrays/introduction.md
index 6007d85ac5..825bb0e50d 100644
--- a/concepts/arrays/introduction.md
+++ b/concepts/arrays/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
 
 ```csharp
diff --git a/concepts/attributes/about.md b/concepts/attributes/about.md
index d9b8a4f4f9..d57e2b9e7b 100644
--- a/concepts/attributes/about.md
+++ b/concepts/attributes/about.md
@@ -1,3 +1,5 @@
+# About
+
 A [C# `Attribute`][attribute-concept] provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported][attribute-targets] declarations.
 
 You can apply [an attribute][attribute] to a declaration by adding it between brackets `[]` before the declaration, the following example uses both a `ClassAttribute` and a `FieldAttribute`:
diff --git a/concepts/attributes/introduction.md b/concepts/attributes/introduction.md
index f590e5ecda..b6793a16c1 100644
--- a/concepts/attributes/introduction.md
+++ b/concepts/attributes/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A [C# `Attribute`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/) provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) declarations.
 
 You can apply an attribute by adding it on the line before the declaration using a `ClassAttribute` and a `FieldAttribute`:
diff --git a/concepts/basics/about.md b/concepts/basics/about.md
index e97a237064..7c4eaa1331 100644
--- a/concepts/basics/about.md
+++ b/concepts/basics/about.md
@@ -1,3 +1,5 @@
+# About
+
 C# is a statically-typed language, which means that everything has a type at compile-time. Choosing a name for a [variable][variable] is referred to as defining a variable. Once a variable is defined, setting or updating a value is called variable assignment. A variable can be defined either by explicitly specifying its type, or by using the [`var` keyword][var] to have the C# compiler infer its type based on the assigned value. The use of `var` is known as _type inference_.
 
 ```csharp
diff --git a/concepts/basics/introduction.md b/concepts/basics/introduction.md
index a0da40de82..10a7abb2be 100644
--- a/concepts/basics/introduction.md
+++ b/concepts/basics/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent:
 
 ```csharp
diff --git a/concepts/bit-manipulation/about.md b/concepts/bit-manipulation/about.md
index c3e5499a9b..617004e799 100644
--- a/concepts/bit-manipulation/about.md
+++ b/concepts/bit-manipulation/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: See #2112. We need to reconsider the text below now that it is a stand alone concept or maybe bitwise manipulation should be introduced in a separate exercise and the flag-enums exercise and concept should take that as a dependency showing how bitwise manipulation is used in the context of enums.
 
 To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags.
diff --git a/concepts/bit-manipulation/introduction.md b/concepts/bit-manipulation/introduction.md
index 8229d6b196..64437acc2a 100644
--- a/concepts/bit-manipulation/introduction.md
+++ b/concepts/bit-manipulation/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for bit-manipulation concept
diff --git a/concepts/booleans/about.md b/concepts/booleans/about.md
index 368f4d97db..7047e94a7e 100644
--- a/concepts/booleans/about.md
+++ b/concepts/booleans/about.md
@@ -1,3 +1,5 @@
+# About
+
 Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`.
 
 C# supports three [boolean operators][operators]: `!` (NOT), `&&` (AND), and `||` (OR). The `&&` and `||` operators use _short-circuit evaluation_, which means that the right-hand side of the operator is only evaluated when needed.
diff --git a/concepts/booleans/introduction.md b/concepts/booleans/introduction.md
index 5341d27350..f41347edbd 100644
--- a/concepts/booleans/introduction.md
+++ b/concepts/booleans/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`.
 
 C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR).
diff --git a/concepts/casting/about.md b/concepts/casting/about.md
index 96fffe3d56..b29ee70c35 100644
--- a/concepts/casting/about.md
+++ b/concepts/casting/about.md
@@ -1,3 +1,5 @@
+# About
+
 Casting and type conversion [are different ways of changing an expression from one data type to another][wiki-casting].
 
 The [C# documentation][type-testing-and-cast-operators] classifies type conversion as the use of the [`as` operator][as-operator] or [`is` operator][is-operator]. Casting is defined as the use of the [cast operator][cast-operator].
diff --git a/concepts/casting/introduction.md b/concepts/casting/introduction.md
index d05ff9408e..f2643ac03c 100644
--- a/concepts/casting/introduction.md
+++ b/concepts/casting/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Casting and type conversion are different ways of changing an expression from one data type to another.
 
 An expression can be cast to another type with the cast operator `()`.
diff --git a/concepts/chars/about.md b/concepts/chars/about.md
index 6698111f2e..8430f64d9c 100644
--- a/concepts/chars/about.md
+++ b/concepts/chars/about.md
@@ -1,3 +1,5 @@
+# About
+
 `char`s are generally easy to use. They can be extracted from strings, added back
 (by means of a string builder), defined and initialised using literals with single quotes, as in `char ch = 'A';`
 , assigned and compared.
diff --git a/concepts/chars/introduction.md b/concepts/chars/introduction.md
index cf7285da07..d361c4f546 100644
--- a/concepts/chars/introduction.md
+++ b/concepts/chars/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text.
 Multiple `char`s can comprise a string such as `"word"` or `char`s can be
 processed independently. Their literals have single quotes e.g. `'A'`.
diff --git a/concepts/classes/about.md b/concepts/classes/about.md
index a5b951d5db..1b9ac3c527 100644
--- a/concepts/classes/about.md
+++ b/concepts/classes/about.md
@@ -1,3 +1,5 @@
+# About
+
 The primary object-oriented construct in C# is the _class_, which is a combination of data ([_fields_][fields]) and behavior ([_methods_][methods]). The fields and methods of a class are known as its _members_.
 
 Access to members can be restricted through access modifiers, the two most common ones being:
diff --git a/concepts/classes/introduction.md b/concepts/classes/introduction.md
index e3770a9229..bd1f6552d8 100644
--- a/concepts/classes/introduction.md
+++ b/concepts/classes/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_.
 
 Access to members can be restricted through access modifiers, the two most common ones being:
diff --git a/concepts/compound-assignment/about.md b/concepts/compound-assignment/about.md
index ab4272662a..7a738936c3 100644
--- a/concepts/compound-assignment/about.md
+++ b/concepts/compound-assignment/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: See issue #2112. I think we need a different exercise to introduce compound assignments (one that shows it being used in a more conventional numeric or string context. flag-enums could then take that as a dependency and show how it is used in this more unusual context.
 
 The bitwise operators can also be used as [compound assignments][compound-assignment], which are a shorthand notation where `x = op y` can be written as `x op= y`:
diff --git a/concepts/compound-assignment/introduction.md b/concepts/compound-assignment/introduction.md
index 2fee3d9ef0..c66432240b 100644
--- a/concepts/compound-assignment/introduction.md
+++ b/concepts/compound-assignment/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for compound-assignment concept
diff --git a/concepts/const-readonly/about.md b/concepts/const-readonly/about.md
index b027443617..624733bb5a 100644
--- a/concepts/const-readonly/about.md
+++ b/concepts/const-readonly/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on const-readonly concept
diff --git a/concepts/const-readonly/introduction.md b/concepts/const-readonly/introduction.md
index 940fa714dc..565a9ffb91 100644
--- a/concepts/const-readonly/introduction.md
+++ b/concepts/const-readonly/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for const-readonly concept
diff --git a/concepts/constants/about.md b/concepts/constants/about.md
index bf8ef965da..6acea2bb62 100644
--- a/concepts/constants/about.md
+++ b/concepts/constants/about.md
@@ -1,3 +1,5 @@
+# About
+
 #### const
 
 The [`const`][constants] modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
diff --git a/concepts/constants/introduction.md b/concepts/constants/introduction.md
index 9012326167..1959d7a56b 100644
--- a/concepts/constants/introduction.md
+++ b/concepts/constants/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
 
 ```csharp
diff --git a/concepts/constructors/about.md b/concepts/constructors/about.md
index ca5bb2aeda..0a77c6632a 100644
--- a/concepts/constructors/about.md
+++ b/concepts/constructors/about.md
@@ -1,3 +1,5 @@
+# About
+
 Creating an instance of a _class_ is done by calling its [_constructor_][constructors] through the [`new` operator][new]. A constructor is a special type of method whose goal is to initialize a newly created instance. [Constructors look like regular methods][constructor-syntax], but without a return type and with a name that matches the classes' name.
 
 ```csharp
diff --git a/concepts/constructors/introduction.md b/concepts/constructors/introduction.md
index 1fbd17c9ef..ae9a354400 100644
--- a/concepts/constructors/introduction.md
+++ b/concepts/constructors/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name.
 
 ```csharp
diff --git a/concepts/datetimes/about.md b/concepts/datetimes/about.md
index d92f0b6f52..78fa88ad75 100644
--- a/concepts/datetimes/about.md
+++ b/concepts/datetimes/about.md
@@ -1,3 +1,5 @@
+# About
+
 A `DateTime` in C# is an immutable object that contains both date _and_ time information. The date and time information can be accessed through its built-in [properties][properties].
 
 Manipulating a `DateTime` can be done by calling one of its [methods][methods]. As `DateTime` values can never change after having been defined, all methods that appear to modify a `DateTime` will actually return a new `DateTime`.
diff --git a/concepts/datetimes/introduction.md b/concepts/datetimes/introduction.md
index 7ba7a7786f..20e7d625b9 100644
--- a/concepts/datetimes/introduction.md
+++ b/concepts/datetimes/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`.
 
 The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`.
diff --git a/concepts/defensive-copying/about.md b/concepts/defensive-copying/about.md
index 58d920b686..0ee54059b7 100644
--- a/concepts/defensive-copying/about.md
+++ b/concepts/defensive-copying/about.md
@@ -1,3 +1,5 @@
+# About
+
 Imagine you have a code-base of several hundred thousand lines. You are passed the dictionary of developers into some method you are developing. Perhaps you have been tasked with printing out details of privileged developers. You decide to blank out the eye color in the dictionary to protect the developers' privacy. Unless a [deep copy][so-deep-copy] of the dictionary was made in the `Authenticator.GetDevelopers()` method, or, even better, it was wrapped in a read-only collection then you will have just trashed the authenticator.
 
 This follows the principle of [defensive copying][defensive-copying]. You can make sure your formal API is not circumvented by avoiding exposure to callers of internal writeable state.
diff --git a/concepts/defensive-copying/introduction.md b/concepts/defensive-copying/introduction.md
index f920e8fda7..3a18bde61b 100644
--- a/concepts/defensive-copying/introduction.md
+++ b/concepts/defensive-copying/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 In security sensitive situations (or even simply on a large code-base where developers have different priorities and agendas) you should avoid allowing a class's public API to be circumvented by accepting and storing a method's mutable parameters or by exposing a mutable member of a class through a return value or as an `out` parameter.
diff --git a/concepts/dictionaries/about.md b/concepts/dictionaries/about.md
index 90fb70e4ea..d395cf9570 100644
--- a/concepts/dictionaries/about.md
+++ b/concepts/dictionaries/about.md
@@ -1,3 +1,5 @@
+# About
+
 Dictionaries, like their equivalents in other languages such as maps or associative arrays, store key/value pairs such that a value can be retrieved or changed directly by passing the key to the dictionary's indexer property.
 
 In addition key/value pairs can be added and removed from the dictionary. Keys, values and key/value pairs can be enumerated.
diff --git a/concepts/dictionaries/introduction.md b/concepts/dictionaries/introduction.md
index 91a2a23020..ecbc0f2a27 100644
--- a/concepts/dictionaries/introduction.md
+++ b/concepts/dictionaries/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages.
 
 A dictionary can be created as follows:
diff --git a/concepts/do-while-loops/about.md b/concepts/do-while-loops/about.md
index be7bfe5c4b..4f24b7b7f3 100644
--- a/concepts/do-while-loops/about.md
+++ b/concepts/do-while-loops/about.md
@@ -1,3 +1,5 @@
+# About
+
 To repeatedly execute logic, one can use loops. If the code in a loop should always be executed at least one, a `do/while` loop can be used:
 
 ```csharp
diff --git a/concepts/do-while-loops/introduction.md b/concepts/do-while-loops/introduction.md
index 87655882d1..46cf941a8e 100644
--- a/concepts/do-while-loops/introduction.md
+++ b/concepts/do-while-loops/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 An less commonly used alternative to the above syntax is a `do-while` loop:
 
 ```csharp
diff --git a/concepts/enums/about.md b/concepts/enums/about.md
index c0e8fcda83..06678469bd 100644
--- a/concepts/enums/about.md
+++ b/concepts/enums/about.md
@@ -1,3 +1,5 @@
+# About
+
 You can use [Enumeration types][enumeration types] whenever you have a fixed set of constant values. Using an `enum` gives one a type-safe way of interacting with constant values. Defining an enum is done through the `enum` keyword. An enum member is referred to by prepending it with the enum name and a dot (e.g. `Status.Active`).
 
 Each enum member is an association of a name and an `int` value. If the first member does not have an explicit value, its value is set to `0`. If no value is explicitly defined for an enum member, its value is automatically assigned to the previous member's value plus `1`.
diff --git a/concepts/enums/introduction.md b/concepts/enums/introduction.md
index 9f383a26bb..1199eb6983 100644
--- a/concepts/enums/introduction.md
+++ b/concepts/enums/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows:
 
 ```csharp
diff --git a/concepts/equality/about.md b/concepts/equality/about.md
index 2895dd239a..a30fd17b02 100644
--- a/concepts/equality/about.md
+++ b/concepts/equality/about.md
@@ -1,3 +1,5 @@
+# About
+
 The coding exercise illustrates a number of properties of equality in C#:
 
 ### `Object.Equals()`
diff --git a/concepts/equality/introduction.md b/concepts/equality/introduction.md
index c43fde97d1..c27abfcc8c 100644
--- a/concepts/equality/introduction.md
+++ b/concepts/equality/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`.
 
 Reference types (Instances of classes) are compared using the `Equals()` method inherited from `Object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `Object`'s implementation will suffice. If not, you need to override `object.Equals()`.
diff --git a/concepts/exception-filtering/about.md b/concepts/exception-filtering/about.md
index cabc830e18..1c311bfdcf 100644
--- a/concepts/exception-filtering/about.md
+++ b/concepts/exception-filtering/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: This may need a more rounded introduction to filtering here.
 `when` is the keyword in filtering exceptions. It is placed after the catch
 statement and can take a boolean expression containing any values in scope at the time. They don't just have to be members of the exception itself. If the type of the exception matches and the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked.
diff --git a/concepts/exception-filtering/introduction.md b/concepts/exception-filtering/introduction.md
index 69e80eaa79..ab7d45b63d 100644
--- a/concepts/exception-filtering/introduction.md
+++ b/concepts/exception-filtering/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 `when` is the key word in filtering exceptions. It is placed after the catch
 statement and can take a boolean expression containing any values in scope at the time. If the expression evaluates to true then the block associated with that `catch` statement is executed otherwise the next `catch` statement, if any, is checked.
 
diff --git a/concepts/exceptions/about.md b/concepts/exceptions/about.md
index 2dd4d9e2d4..e3e87a7c90 100644
--- a/concepts/exceptions/about.md
+++ b/concepts/exceptions/about.md
@@ -1,3 +1,5 @@
+# About
+
 It is important to note that `exceptions` should be used in cases where something exceptional happens, an error that needs special handeling. It should not be used for control-flow of a program, as that is considered bad design, which often leads to bad performance and maintainability.
 
 Some of the more common exceptions include `IndexOutOfRangeException`, `ArgumentOutOfRangeException`, `NullReferenceException`, `StackOverflowException`, `ArgumentException`, `InvalidOperationException` and `DivideByZeroException`.
diff --git a/concepts/exceptions/introduction.md b/concepts/exceptions/introduction.md
index 002ea03980..effb2cf38c 100644
--- a/concepts/exceptions/introduction.md
+++ b/concepts/exceptions/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes.
 
 In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown.
diff --git a/concepts/explicit-casts/about.md b/concepts/explicit-casts/about.md
index 6be5afbbe0..a173879202 100644
--- a/concepts/explicit-casts/about.md
+++ b/concepts/explicit-casts/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on explicit-casts concept
diff --git a/concepts/explicit-casts/introduction.md b/concepts/explicit-casts/introduction.md
index c2a17943d1..ed04dec7a6 100644
--- a/concepts/explicit-casts/introduction.md
+++ b/concepts/explicit-casts/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for explicit-casts concept
diff --git a/concepts/expression-bodied-members/about.md b/concepts/expression-bodied-members/about.md
index 8ee331576b..616b837f8a 100644
--- a/concepts/expression-bodied-members/about.md
+++ b/concepts/expression-bodied-members/about.md
@@ -1,3 +1,5 @@
+# About
+
 Many [types of struct and class members][expression-bodied-members] (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements.
 
 ```csharp
diff --git a/concepts/expression-bodied-members/introduction.md b/concepts/expression-bodied-members/introduction.md
index d5a9a75e37..67d4af2f7c 100644
--- a/concepts/expression-bodied-members/introduction.md
+++ b/concepts/expression-bodied-members/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements.
 
 Methods and read-only properties are amongst the members that can be defined with expression bodies.
diff --git a/concepts/flag-enums/about.md b/concepts/flag-enums/about.md
index b92279bc84..170f68417b 100644
--- a/concepts/flag-enums/about.md
+++ b/concepts/flag-enums/about.md
@@ -1,3 +1,5 @@
+# About
+
 To allow a single enum instance to represent multiple values (usually referred to as _flags_), one can annotate the enum with the `[Flags]` attribute. By carefully assigning the values of the enum members such that specific bits are set to `1`, bitwise operators can be used to set or unset flags.
 
 ```csharp
diff --git a/concepts/flag-enums/introduction.md b/concepts/flag-enums/introduction.md
index f704ad50b5..704f16300e 100644
--- a/concepts/flag-enums/introduction.md
+++ b/concepts/flag-enums/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The C# [`enum` type](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/enum) represents a fixed set of named constants (an enumeration).
 
 Normally, one `enum` member can only refer to exactly one of those named constants. However, sometimes it is useful to refer to more than one constant. To do so, one can annotate the `enum` with the [`Flags` attribute](https://docs.microsoft.com/en-us/dotnet/api/system.flagsattribute?view=net-5.0). A _flags_ enum's constants are interpreted as bitwise _flags_ and therefor indicates the enum supports the bitwise operators and additional features like the method `Enum.HasFlag()`.
diff --git a/concepts/floating-point-numbers/about.md b/concepts/floating-point-numbers/about.md
index 36b02423b0..f89b04a51c 100644
--- a/concepts/floating-point-numbers/about.md
+++ b/concepts/floating-point-numbers/about.md
@@ -1,3 +1,5 @@
+# About
+
 There are three floating-point types in C#: `double`, `float` and `decimal`. The most commonly used type is `double`, whereas `decimal` is normally used when working with monetary data. A `double` is written as `2.45` or `2.45d`, a `float` as `2.45f` and a decimal as `2.45m`.
 
 Each floating-point type has its own [precision, approximate range and size][docs-microsoft.com-characteristics-of-the-floating-point-types].
diff --git a/concepts/floating-point-numbers/introduction.md b/concepts/floating-point-numbers/introduction.md
index 75294a6e65..5c980b5fad 100644
--- a/concepts/floating-point-numbers/introduction.md
+++ b/concepts/floating-point-numbers/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.
 
 Different floating-point types can store different numbers of digits after the digit separator - this is referred to as its precision.
diff --git a/concepts/for-loops/about.md b/concepts/for-loops/about.md
index b46d9d77d7..d0b115e7aa 100644
--- a/concepts/for-loops/about.md
+++ b/concepts/for-loops/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts.
 Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
 
diff --git a/concepts/for-loops/introduction.md b/concepts/for-loops/introduction.md
index 7e35bb6739..328bdc6e70 100644
--- a/concepts/for-loops/introduction.md
+++ b/concepts/for-loops/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 If you want more control over which values to iterate over, a `for` loop can be used:
 
 ```csharp
diff --git a/concepts/foreach-loops/about.md b/concepts/foreach-loops/about.md
index b46d9d77d7..d0b115e7aa 100644
--- a/concepts/foreach-loops/about.md
+++ b/concepts/foreach-loops/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md files and links.json files are the same for arrays, for-loops and foreach. Consider how to prise these apart of otherwise treat these closely coupled concepts.
 Data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
 
diff --git a/concepts/foreach-loops/introduction.md b/concepts/foreach-loops/introduction.md
index 694b15c182..5c6e9a6e56 100644
--- a/concepts/foreach-loops/introduction.md
+++ b/concepts/foreach-loops/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The fact that an array is also a _collection_ means that, besides accessing values by index, you can iterate over _all_ its values using a `foreach` loop:
 
 ```csharp
diff --git a/concepts/generic-types/about.md b/concepts/generic-types/about.md
index 99682785d4..7abf448460 100644
--- a/concepts/generic-types/about.md
+++ b/concepts/generic-types/about.md
@@ -1,3 +1,5 @@
+# About
+
 Lists are an example of generic classes. You will also see `HashSet` and `Dictionary` in early exercises.
 
 More [advanced generic techniques][generics] are discussed in (TODO cross-ref-tba) including creating your own generics.
diff --git a/concepts/generic-types/introduction.md b/concepts/generic-types/introduction.md
index 19803e6658..0506858589 100644
--- a/concepts/generic-types/introduction.md
+++ b/concepts/generic-types/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 A collection definition typically includes a place holder in angle brackets, often `T` by convention. Such a collection is referred to as a generic type. This allows the collection user to specify what type of items to store in the collection. In the above example code we are instantiating a list of strings.
diff --git a/concepts/if-statements/about.md b/concepts/if-statements/about.md
index e5a4365d41..63a3db7b1f 100644
--- a/concepts/if-statements/about.md
+++ b/concepts/if-statements/about.md
@@ -1,3 +1,5 @@
+# About
+
 An `if` statement can be used to conditionally execute code. The condition of an `if` statement must be of type `bool`. C# has no concept of _truthy_ values.
 
 The most common way to do this in C# is by using [an `if/else` statement][if-else]:
diff --git a/concepts/if-statements/introduction.md b/concepts/if-statements/introduction.md
index 640e904c2d..cff8f65396 100644
--- a/concepts/if-statements/introduction.md
+++ b/concepts/if-statements/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In this exercise you must conditionally execute logic. The most common way to do this in C# is by using an `if/else` statement:
 
 ```csharp
diff --git a/concepts/indexers/about.md b/concepts/indexers/about.md
index dd326541f0..7acd2cfb9f 100644
--- a/concepts/indexers/about.md
+++ b/concepts/indexers/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on indexers concept
diff --git a/concepts/indexers/introduction.md b/concepts/indexers/introduction.md
index b3c1d000de..8d8183e058 100644
--- a/concepts/indexers/introduction.md
+++ b/concepts/indexers/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for indexers concept
diff --git a/concepts/inheritance/about.md b/concepts/inheritance/about.md
index 74e8393691..1d0bc35d9b 100644
--- a/concepts/inheritance/about.md
+++ b/concepts/inheritance/about.md
@@ -1,3 +1,5 @@
+# About
+
 In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class.
 
 Parent classes can provide functionality to derived classes in three ways:
diff --git a/concepts/inheritance/introduction.md b/concepts/inheritance/introduction.md
index 32a4f8d3b0..231a4f9b25 100644
--- a/concepts/inheritance/introduction.md
+++ b/concepts/inheritance/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class.
 
 Parent classes can provide functionality to derived classes in three ways:
diff --git a/concepts/integral-numbers/about.md b/concepts/integral-numbers/about.md
index a233472422..86cad8b25b 100644
--- a/concepts/integral-numbers/about.md
+++ b/concepts/integral-numbers/about.md
@@ -1,3 +1,5 @@
+# About
+
 C#, like many statically typed languages, provides a number of types that represent integers, each with its own [range of values][integral-numeric-types]. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types.
 
 Each of the above types is paired with an unsigned equivalent: `sbyte`/`byte`, `short`/`ushort`, `int`/`uint` and `long`/`ulong`. In all cases the range of the values is from 0 to the negative signed maximum times 2 plus 1.
diff --git a/concepts/integral-numbers/introduction.md b/concepts/integral-numbers/introduction.md
index a134fd0930..714616a7a8 100644
--- a/concepts/integral-numbers/introduction.md
+++ b/concepts/integral-numbers/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types.
 
 The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits.
diff --git a/concepts/interfaces/about.md b/concepts/interfaces/about.md
index fecb4c8ef8..bfaa79cb58 100644
--- a/concepts/interfaces/about.md
+++ b/concepts/interfaces/about.md
@@ -1,3 +1,5 @@
+# About
+
 [`interfaces`][interfaces] are the primary means of [decoupling][wiki-loose-coupling] the uses of a class from its implementation. This decoupling provides flexibility for maintenance of the implementation and helps support type safe generic behavior.
 
 The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided.
diff --git a/concepts/interfaces/introduction.md b/concepts/interfaces/introduction.md
index 1bfe42581d..1850f1e8ff 100644
--- a/concepts/interfaces/introduction.md
+++ b/concepts/interfaces/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion.
 
 The syntax of an interface is similar to that of a class or struct except that methods and properties appear as the signature only and no body is provided.
diff --git a/concepts/lists/about.md b/concepts/lists/about.md
index aaf0658df7..eeaa64b525 100644
--- a/concepts/lists/about.md
+++ b/concepts/lists/about.md
@@ -1,3 +1,5 @@
+# About
+
 Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as [`List`][lists-docs] where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists.
 
 ```csharp
diff --git a/concepts/lists/introduction.md b/concepts/lists/introduction.md
index a4cbeb6b64..e6a0a19415 100644
--- a/concepts/lists/introduction.md
+++ b/concepts/lists/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists.
 
 Items can be added to and removed from lists. They grow and shrink as necessary.
diff --git a/concepts/memory-allocation/about.md b/concepts/memory-allocation/about.md
index 36a70fe8ce..97d7ceee3a 100644
--- a/concepts/memory-allocation/about.md
+++ b/concepts/memory-allocation/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on memory-allocation concept
diff --git a/concepts/memory-allocation/introduction.md b/concepts/memory-allocation/introduction.md
index 7f76d1971a..391bae5b54 100644
--- a/concepts/memory-allocation/introduction.md
+++ b/concepts/memory-allocation/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for memory-allocation concept
diff --git a/concepts/method-overloading/about.md b/concepts/method-overloading/about.md
index 7d81482cfb..b481508a51 100644
--- a/concepts/method-overloading/about.md
+++ b/concepts/method-overloading/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case
 [_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
diff --git a/concepts/method-overloading/introduction.md b/concepts/method-overloading/introduction.md
index 419e231fe4..c4ed514c3b 100644
--- a/concepts/method-overloading/introduction.md
+++ b/concepts/method-overloading/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 _Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
 - The number of parameters
diff --git a/concepts/named-arguments/about.md b/concepts/named-arguments/about.md
index 149ed2a78b..b89a20a772 100644
--- a/concepts/named-arguments/about.md
+++ b/concepts/named-arguments/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providing a more focused context in each case
 [_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
diff --git a/concepts/named-arguments/introduction.md b/concepts/named-arguments/introduction.md
index 24bdcdb12d..26dd7b7563 100644
--- a/concepts/named-arguments/introduction.md
+++ b/concepts/named-arguments/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 So far we have seen that the arguments passed into a method are matched to the method are matched to the method's declared parameters based on position. An alternative approach, particularly where a routine takes a large number of arguments, the caller can match arguments by specifying the declared parameter's identifier.
 
 The following illustrates the syntax:
diff --git a/concepts/namespaces/about.md b/concepts/namespaces/about.md
index 0973200a1d..828f04fd47 100644
--- a/concepts/namespaces/about.md
+++ b/concepts/namespaces/about.md
@@ -1,3 +1,5 @@
+# About
+
 It is unlikely that you will come across much production code that does not make use of namespaces.
 
 An example of the syntax is:
diff --git a/concepts/namespaces/introduction.md b/concepts/namespaces/introduction.md
index ccfd49113a..0e2879c6a8 100644
--- a/concepts/namespaces/introduction.md
+++ b/concepts/namespaces/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base.
 
 The syntax is as follows:
diff --git a/concepts/nested-types/about.md b/concepts/nested-types/about.md
index c0f7dce25a..50748f1c74 100644
--- a/concepts/nested-types/about.md
+++ b/concepts/nested-types/about.md
@@ -1,3 +1,5 @@
+# About
+
 C# types can be defined within the scope of a class or struct. The enclosing type provides a kind name space. Access to the type is through the enclosing type with dot syntax.
 
 ```csharp
diff --git a/concepts/nested-types/introduction.md b/concepts/nested-types/introduction.md
index 1edafdd14b..8c815d506b 100644
--- a/concepts/nested-types/introduction.md
+++ b/concepts/nested-types/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax.
 
 ```csharp
diff --git a/concepts/nullability/about.md b/concepts/nullability/about.md
index a7b26495cb..961eb1cf2a 100644
--- a/concepts/nullability/about.md
+++ b/concepts/nullability/about.md
@@ -1,3 +1,5 @@
+# About
+
 In C#, the [`null` literal][null-keyword] is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values.
 
 Prior to C# 8.0, reference types were always nullable and value types were not. A [value type can be made nullable][nullable-value-types] though by appending it with a question mark (`?`).
diff --git a/concepts/nullability/introduction.md b/concepts/nullability/introduction.md
index 6ce9868e2e..79dacc2a7c 100644
--- a/concepts/nullability/introduction.md
+++ b/concepts/nullability/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values.
 
 Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`).
diff --git a/concepts/numbers/about.md b/concepts/numbers/about.md
index c16655f886..3bd109daeb 100644
--- a/concepts/numbers/about.md
+++ b/concepts/numbers/about.md
@@ -1,3 +1,5 @@
+# About
+
 One of the key aspects of working with numbers in C# is the distinction between integers (numbers with no digits after the decimal separator) and floating-point numbers (numbers with zero or more digits after the decimal separator).
 
 The two most commonly used numeric types in C# are `int` (a 32-bit integer) and `double` (a 64-bit floating-point number).
diff --git a/concepts/numbers/introduction.md b/concepts/numbers/introduction.md
index 52f5a0bd54..0dfe935f3a 100644
--- a/concepts/numbers/introduction.md
+++ b/concepts/numbers/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 There are two different types of numbers in C#:
 
 - Integers: numbers with no digits behind the decimal separator (whole numbers). Examples are `-6`, `0`, `1`, `25`, `976` and `500000`.
diff --git a/concepts/object-initializers/about.md b/concepts/object-initializers/about.md
index 248bf7f518..301a4d4cc4 100644
--- a/concepts/object-initializers/about.md
+++ b/concepts/object-initializers/about.md
@@ -1,3 +1,5 @@
+# About
+
 Object initializers are an alternative to constructors. The syntax is a comma separated list of field name=value pairs, illustrated below:
 
 ```csharp
diff --git a/concepts/object-initializers/introduction.md b/concepts/object-initializers/introduction.md
index 25b3b07ef5..b9d21b15df 100644
--- a/concepts/object-initializers/introduction.md
+++ b/concepts/object-initializers/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets:
 
 ```csharp
diff --git a/concepts/operator-overloading/about.md b/concepts/operator-overloading/about.md
index d0fb4ff52b..2ac3a4d5af 100644
--- a/concepts/operator-overloading/about.md
+++ b/concepts/operator-overloading/about.md
@@ -1,3 +1,5 @@
+# About
+
 The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_.
 
 This [article][operator-overloading] is a thorough discussion of the syntax as well as which operators can be overloaded and those that can't.
diff --git a/concepts/operator-overloading/introduction.md b/concepts/operator-overloading/introduction.md
index 9c72dea800..c570dd8524 100644
--- a/concepts/operator-overloading/introduction.md
+++ b/concepts/operator-overloading/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_.
 
 Most operators have the form:
diff --git a/concepts/optional-parameters/about.md b/concepts/optional-parameters/about.md
index 7d81482cfb..b481508a51 100644
--- a/concepts/optional-parameters/about.md
+++ b/concepts/optional-parameters/about.md
@@ -1,3 +1,5 @@
+# About
+
 TODO: about.md and link.json files - method-overloading == named-arguments == optional-parameters - consider providiing a more focused context in each case
 [_Method overloading_][member-overloading] allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
 
diff --git a/concepts/optional-parameters/introduction.md b/concepts/optional-parameters/introduction.md
index 5a8afa0d25..129b62140d 100644
--- a/concepts/optional-parameters/introduction.md
+++ b/concepts/optional-parameters/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A method parameter can be made optional by assigning it a default value. When calling a method with optional parameters, the caller is not required to pass a value for them. If no value is passed for an optional parameter, its default value will be used.
 
 Optional parameters _must_ be at the end of the parameter list; they cannot be followed by non-optional parameters.
diff --git a/concepts/ordering/about.md b/concepts/ordering/about.md
index 9ce566ba38..5d3148209c 100644
--- a/concepts/ordering/about.md
+++ b/concepts/ordering/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on ordering concept
diff --git a/concepts/ordering/introduction.md b/concepts/ordering/introduction.md
index 9f877ecd2a..31f3601cb9 100644
--- a/concepts/ordering/introduction.md
+++ b/concepts/ordering/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 The `IComparable` interface can be implemented where a default generic sort order in collections is required.
diff --git a/concepts/overflow/about.md b/concepts/overflow/about.md
index 72f48e559f..ab55e4b8b0 100644
--- a/concepts/overflow/about.md
+++ b/concepts/overflow/about.md
@@ -1,3 +1,5 @@
+# About
+
 The exercise shows the behavior of various numeric types when they overflow, i.e. when their capacity is insufficient to contain the value resulting from a computation such as an arithmetic operation or cast.
 
 - unsigned [integers][integral-numeric-types] (`byte`, `ushort`, `uint`, `ulong`) will wrap around to zero (the type's maximum value + 1 acts as a modulus) unless [broadly speaking][checked-compiler-setting] they appear within a [`checked`][checked-and-unchecked] block in which case an instance of `OverflowException` is thrown. `int` and `long` will behave similarly except that they wrap around to `int.MinValue` and `long.minValue` respectively.
diff --git a/concepts/overflow/introduction.md b/concepts/overflow/introduction.md
index a2313bf95e..20480ae5df 100644
--- a/concepts/overflow/introduction.md
+++ b/concepts/overflow/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type.
 
 Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances.
diff --git a/concepts/parameters/about.md b/concepts/parameters/about.md
index 019f5aafc3..463db3522a 100644
--- a/concepts/parameters/about.md
+++ b/concepts/parameters/about.md
@@ -1,3 +1,5 @@
+# About
+
 The coding exercise illustrates a number of properties of parameters:
 
 - Parameters [passed][passing-parameters] without a modifier (such as `out` or `ref`) are passed by value. That is to say that the parameter can be used and assigned to in the called method but any changes will have no effect on the caller.
diff --git a/concepts/parameters/introduction.md b/concepts/parameters/introduction.md
index 1c42283f86..37f6df92f1 100644
--- a/concepts/parameters/introduction.md
+++ b/concepts/parameters/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 This exercise discusses some details of method parameters and their use in C#.
 
 Parameters convey information from a calling method to a called method.
diff --git a/concepts/properties/about.md b/concepts/properties/about.md
index dd33bc01ee..afe01e847e 100644
--- a/concepts/properties/about.md
+++ b/concepts/properties/about.md
@@ -1,3 +1,5 @@
+# About
+
 The two main types of property are
 
 1. auto-implemented properties where the `get` and `set` accessors have no body.
diff --git a/concepts/properties/introduction.md b/concepts/properties/introduction.md
index 1405dddcca..c5706faf8c 100644
--- a/concepts/properties/introduction.md
+++ b/concepts/properties/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A property in C# is a member of a class that provides access to data within that class.
 Callers can set or retrieve (get) the data. Properties can be either auto-implemented or
 have a backing field. They comprise a set accessor and/or a get accessor.
diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md
index 9257c2c3a3..6091b05a3b 100644
--- a/concepts/randomness/about.md
+++ b/concepts/randomness/about.md
@@ -1,3 +1,5 @@
+# About
+
 In C# applications randomness is generally implemented using the `System.Random` class.
 
 This [article][system-random] is an excellent introduction to the subject.
diff --git a/concepts/randomness/introduction.md b/concepts/randomness/introduction.md
index 264aec91ec..f49401bb66 100644
--- a/concepts/randomness/introduction.md
+++ b/concepts/randomness/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case.
diff --git a/concepts/readonly-collections/about.md b/concepts/readonly-collections/about.md
index 6c85a723ea..42849875db 100644
--- a/concepts/readonly-collections/about.md
+++ b/concepts/readonly-collections/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on readonly-collections concept
diff --git a/concepts/readonly-collections/introduction.md b/concepts/readonly-collections/introduction.md
index 4b42299301..2e593a908e 100644
--- a/concepts/readonly-collections/introduction.md
+++ b/concepts/readonly-collections/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 While the `readonly` modifier prevents the value or reference in a field from being overwritten, it offers no protection for the members of a reference type.
 
 ```csharp
diff --git a/concepts/regular-expressions/about.md b/concepts/regular-expressions/about.md
index ef161ce8ca..2827488151 100644
--- a/concepts/regular-expressions/about.md
+++ b/concepts/regular-expressions/about.md
@@ -1,3 +1,5 @@
+# About
+
 The .NET base class libraries provide the [`Regex`][regex] class for processing of regular expressions.
 
 See this [article][regex-comparison] for a comparison of C# with other flavours of regular expressions.
diff --git a/concepts/regular-expressions/introduction.md b/concepts/regular-expressions/introduction.md
index 1256179199..d00e71bc27 100644
--- a/concepts/regular-expressions/introduction.md
+++ b/concepts/regular-expressions/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 The .NET base class libraries provide the `Regex` class for processing of regular expressions.
diff --git a/concepts/resource-cleanup/about.md b/concepts/resource-cleanup/about.md
index a1ed529cce..ff47c44ac8 100644
--- a/concepts/resource-cleanup/about.md
+++ b/concepts/resource-cleanup/about.md
@@ -1,3 +1,5 @@
+# About
+
 The [`IDisposable`][idisposable] interface is central to resource cleanup and has two significant roles in C#:
 
 - It indicates to users of the implementing class that they are responsible for letting the class know (by calling the [`Dispose()`][dispose] method) that it is no longer required so that it can release any unmanaged resources or reset its internal state as appropriate. This contrasts with the normal approach to cleaning up of allowing the [garbage collector][garbage-collector] to clean everything up (principally, release memory).
diff --git a/concepts/resource-cleanup/introduction.md b/concepts/resource-cleanup/introduction.md
index ffeafbf696..8d01e3c6f6 100644
--- a/concepts/resource-cleanup/introduction.md
+++ b/concepts/resource-cleanup/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset.
diff --git a/concepts/resource-lifetime/about.md b/concepts/resource-lifetime/about.md
index 6b029325c0..8e49ae67f1 100644
--- a/concepts/resource-lifetime/about.md
+++ b/concepts/resource-lifetime/about.md
@@ -1,3 +1,5 @@
+# About
+
 We discussed in (TODO cross-ref-tba) how the `IDispoable` interface helps signal to callers of a class that there are resources or program state that need releasing or resetting in a timely fashion when the object in question is no longer required. In this exercise we have introduced some syntactic sugar, with the `using` keyword, that makes the code less verbose and less likely that significant calls will be omitted.
 
 `using` can be seen as replacing [`try/finally`][try-finally] for some use cases.
diff --git a/concepts/resource-lifetime/introduction.md b/concepts/resource-lifetime/introduction.md
index ee0bef510d..6b15e3632f 100644
--- a/concepts/resource-lifetime/introduction.md
+++ b/concepts/resource-lifetime/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations.
 
 There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement.
diff --git a/concepts/sets/about.md b/concepts/sets/about.md
index bb43f192c2..c3d98d9ca4 100644
--- a/concepts/sets/about.md
+++ b/concepts/sets/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on sets concept
diff --git a/concepts/sets/introduction.md b/concepts/sets/introduction.md
index 8ffeab96e7..bcb6c5e846 100644
--- a/concepts/sets/introduction.md
+++ b/concepts/sets/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 The `HashSet` library class provides a good mechanism for storing unique values.
diff --git a/concepts/string-builder/about.md b/concepts/string-builder/about.md
index 9efe3ba7ff..22e4b17495 100644
--- a/concepts/string-builder/about.md
+++ b/concepts/string-builder/about.md
@@ -1,3 +1,5 @@
+# About
+
 Using `StringBuilder` is seen as hugely preferable to building up strings with multiple repeated concatenations with
 a `+` or `+=` operator. Obviously simple one off concatenations are preferable
 to instantiating a `StringBuilder` for clarity as well as performance. [This][skeet-stringbuilder] is what [Jon Skeet][so-jon-skeet] has to say about performance.
diff --git a/concepts/string-builder/introduction.md b/concepts/string-builder/introduction.md
index e422be5590..bc114ced49 100644
--- a/concepts/string-builder/introduction.md
+++ b/concepts/string-builder/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 `char`s are sometimes used in conjunction with a `StringBuilder` object.
 This object has methods that allow a string to be constructed
 character by character and manipulated. At the end of the process
diff --git a/concepts/string-formatting/about.md b/concepts/string-formatting/about.md
index 575859943d..55379b98e3 100644
--- a/concepts/string-formatting/about.md
+++ b/concepts/string-formatting/about.md
@@ -1,3 +1,5 @@
+# About
+
 Mechanisms for formatting strings are many and various in C#/.NET: everything from simple concatenation of objects through calls to the overridden `object.ToString()` method to use of [`ICustomFormatter`][custom-formatter] (not covered in this exercise).
 
 The two most common mechanisms for formatting strings are [string interpolation][string-interpolation] and [String.Format()][string-format]. The [`StringBuilder`][string-builder] (cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved.
diff --git a/concepts/string-formatting/introduction.md b/concepts/string-formatting/introduction.md
index 10e8993bd9..8f13762b90 100644
--- a/concepts/string-formatting/introduction.md
+++ b/concepts/string-formatting/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation.
 
 ### Composite Formatting
diff --git a/concepts/string-interpolation/about.md b/concepts/string-interpolation/about.md
index e24a721ed0..da925f30f3 100644
--- a/concepts/string-interpolation/about.md
+++ b/concepts/string-interpolation/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on string-interpolation concept
diff --git a/concepts/string-interpolation/introduction.md b/concepts/string-interpolation/introduction.md
index 8363fc87b6..1f83219aed 100644
--- a/concepts/string-interpolation/introduction.md
+++ b/concepts/string-interpolation/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for string-interpolation concept
diff --git a/concepts/strings/about.md b/concepts/strings/about.md
index 92a7332bef..d2c6a37d1d 100644
--- a/concepts/strings/about.md
+++ b/concepts/strings/about.md
@@ -1,3 +1,5 @@
+# About
+
 The key thing to remember about C# strings is that they are immutable objects representing text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance:
 
 ```csharp
diff --git a/concepts/strings/introduction.md b/concepts/strings/introduction.md
index d7d72cd2ec..3ea1d806cb 100644
--- a/concepts/strings/introduction.md
+++ b/concepts/strings/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance:
 
 ```csharp
diff --git a/concepts/structs/about.md b/concepts/structs/about.md
index 05e95c3a4e..353bfc1648 100644
--- a/concepts/structs/about.md
+++ b/concepts/structs/about.md
@@ -1,3 +1,5 @@
+# About
+
 C# `struct`s are closely related `class`s. They have state and behavior. They can have the same kinds of members: constructors, methods, fields, properties, etc.
 
 Fields and properties can be simple types, `struct`s or reference types. `struct`s observe the same rules about scope, read/write rules and access levels as do `class`s.
diff --git a/concepts/structs/introduction.md b/concepts/structs/introduction.md
index 6b1142d00f..d131de15d0 100644
--- a/concepts/structs/introduction.md
+++ b/concepts/structs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.
 
 ```csharp
diff --git a/concepts/switch-expressions/about.md b/concepts/switch-expressions/about.md
index fe814228ea..6644cd3c4d 100644
--- a/concepts/switch-expressions/about.md
+++ b/concepts/switch-expressions/about.md
@@ -1,3 +1,5 @@
+# About
+
 [Switch expressions][switch-expressions] behave in a similar manner to [switch statements][switch-statements] covered in (TODO cross-ref-tba switch statements). They support a kind of decision table that maps input conditions to actions or values.
 
 At the core of the switch expression is _pattern matching_. In the coding exercise we matched values against `const` patterns. In this case the inputs to the `switch` are a _range expression_ which is matched to const values and the values used by the _case guards_.
diff --git a/concepts/switch-expressions/introduction.md b/concepts/switch-expressions/introduction.md
index e8a499e31d..bccbab3ed5 100644
--- a/concepts/switch-expressions/introduction.md
+++ b/concepts/switch-expressions/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A switch expression can match a value to one case in a set of patterns and return the associated value or take the associated action. The association is denoted by the `=>` symbol. In addition, each pattern can have an optional case guard introduced with the `when` keyword. The case guard expression must evaluate to true for that "arm" of the switch to be selected. The cases (also known as _switch arms_) are evaluated in text order and the process is cut short and the associated value is returned as soon as a match is found.
 
 ```csharp
diff --git a/concepts/switch-statements/about.md b/concepts/switch-statements/about.md
index 8261c86e02..11018155cf 100644
--- a/concepts/switch-statements/about.md
+++ b/concepts/switch-statements/about.md
@@ -1,3 +1,5 @@
+# About
+
 Switch statements have a venerable [history][wiki-switch] in programming languages. They were introduced in [`C`][c-switch] where they were prized for their speed. That speed came at the cost of functionality which was very constrained. In C# the role of the switch statement has been expanded beyond integers. Switch statements can encompass any arbitrary type, value or reference.
 
 If you are coming from a functional language then working with switch statements (and [switch expressions][switch-expression] discussed elsewhere) is the nearest you will get in C# to using discriminated unions and pattern matching. However, they have nowhere near the discriminated union's power to enforce type safety.
diff --git a/concepts/switch-statements/introduction.md b/concepts/switch-statements/introduction.md
index 8395a6f1c9..dc4cf3c75a 100644
--- a/concepts/switch-statements/introduction.md
+++ b/concepts/switch-statements/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program".
 
 The mechanism involves the following keywords: `switch`, `case`, `break` and `default`.
diff --git a/concepts/ternary-operators/about.md b/concepts/ternary-operators/about.md
index 39e4720262..5feddf9c3a 100644
--- a/concepts/ternary-operators/about.md
+++ b/concepts/ternary-operators/about.md
@@ -1,3 +1,5 @@
+# About
+
 [Ternary operators][ternary-operators] allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone.
 
 The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`).
diff --git a/concepts/ternary-operators/introduction.md b/concepts/ternary-operators/introduction.md
index 96c22f0dad..0e68ad7557 100644
--- a/concepts/ternary-operators/introduction.md
+++ b/concepts/ternary-operators/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Ternary operators allow if-conditions to be defined in expressions rather than statement blocks. This echoes functional programming approaches and can often make code more expressive and less error-prone.
 
 The ternary operator combines 3 expressions: a condition followed by an expression to be evaluated and returned if the condition is true (the `if` part, introduced by `?`) and an expression to be evaluated and returned if the condition is false (the `else` part, introduced by `:`).
diff --git a/concepts/throw-expressions/about.md b/concepts/throw-expressions/about.md
index ce681c08fb..261f07dde5 100644
--- a/concepts/throw-expressions/about.md
+++ b/concepts/throw-expressions/about.md
@@ -1,3 +1,5 @@
+# About
+
 [`throw` expressions][throw-expressions] are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions.
 
 ```csharp
diff --git a/concepts/throw-expressions/introduction.md b/concepts/throw-expressions/introduction.md
index 0f6488613a..d25fc93eeb 100644
--- a/concepts/throw-expressions/introduction.md
+++ b/concepts/throw-expressions/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 `throw` expressions are an alternative to `throw` statements and in particular can add to the power of ternary and other compound expressions.
 
 ```csharp
diff --git a/concepts/time/about.md b/concepts/time/about.md
index 1e1a85a43c..47e9bb3948 100644
--- a/concepts/time/about.md
+++ b/concepts/time/about.md
@@ -1,3 +1,5 @@
+# About
+
 Although this exercise investigates the concept of `time` in practice you rarely deal with times on their own. They are almost always dealt with in conjunction with dates. There is no specific separate _time_ type, only [`DateTime`][date-time].
 
 Time-of-day can be expressed with [`TimeSpan`][time-span] (and this is in fact the return type of `DateTime.TimeOfDay`). It is not [purpose made][skeet-time-of-day] so the expressiveness of code can get a bit clunky. For instance, what do you expect time-of-day to be for an instance of `DateTime` that is in UTC form? But, it does the job.
diff --git a/concepts/time/introduction.md b/concepts/time/introduction.md
index b6a66cfb7a..938f344b40 100644
--- a/concepts/time/introduction.md
+++ b/concepts/time/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`.
diff --git a/concepts/timezone/about.md b/concepts/timezone/about.md
index 417fe11300..7814208e39 100644
--- a/concepts/timezone/about.md
+++ b/concepts/timezone/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on timezone concept
diff --git a/concepts/timezone/introduction.md b/concepts/timezone/introduction.md
index 1fc8e89c65..a3ad4312fe 100644
--- a/concepts/timezone/introduction.md
+++ b/concepts/timezone/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The `TimeZoneInfo` class provides routines for handling the differences between time zones. The `TimeZoneInfo` class also contains methods that facilitate dealing with daylight saving time.
 
 The `CultureInfo` class supports locale dependent date time formats.
diff --git a/concepts/tuples/about.md b/concepts/tuples/about.md
index 6b989c403d..6860b8673e 100644
--- a/concepts/tuples/about.md
+++ b/concepts/tuples/about.md
@@ -1,3 +1,5 @@
+# About
+
 In C#, a tuple is a data structure which organizes data, holding two or more fields
 of any type.
 
diff --git a/concepts/tuples/introduction.md b/concepts/tuples/introduction.md
index 88510ef0c5..fdef63ec8a 100644
--- a/concepts/tuples/introduction.md
+++ b/concepts/tuples/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, a tuple is a data structure which organizes data, holding two or more fields
 of any type.
 
diff --git a/concepts/user-defined-exceptions/about.md b/concepts/user-defined-exceptions/about.md
index c9a02dcec2..2ae6f3b7f8 100644
--- a/concepts/user-defined-exceptions/about.md
+++ b/concepts/user-defined-exceptions/about.md
@@ -1,3 +1,5 @@
+# About
+
 A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise. User-defined exceptions can be used in every way like runtime and Microsoft Base Class Library exceptions.
 
 This special treatment applies only to `Exception`-derived classes. You cannot throw instances of any other type.
diff --git a/concepts/user-defined-exceptions/introduction.md b/concepts/user-defined-exceptions/introduction.md
index 8c81022f15..18ee5af4e4 100644
--- a/concepts/user-defined-exceptions/introduction.md
+++ b/concepts/user-defined-exceptions/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise.
 
 User-defined exceptions are often used to carry extra information such as a message and other relevant data to be made available to the catching routines.
diff --git a/concepts/varargs/about.md b/concepts/varargs/about.md
index 43a2024334..ea156d4ef7 100644
--- a/concepts/varargs/about.md
+++ b/concepts/varargs/about.md
@@ -1 +1,3 @@
+# About
+
 TODO: add information on varargs concept
diff --git a/concepts/varargs/introduction.md b/concepts/varargs/introduction.md
index 6398d1241c..91cd733907 100644
--- a/concepts/varargs/introduction.md
+++ b/concepts/varargs/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 TODO: add introduction for varargs concept
diff --git a/concepts/verbatim-strings/about.md b/concepts/verbatim-strings/about.md
index 21fc1b67bd..9d6cfc1e2e 100644
--- a/concepts/verbatim-strings/about.md
+++ b/concepts/verbatim-strings/about.md
@@ -1,3 +1,5 @@
+# About
+
 [Verbatim strings][verbatim-strings] allow multi-line strings. They are introduced with an @. They can be used with string interpolation. Just add a "\$" before the opening quote.
 
 ```csharp
diff --git a/concepts/verbatim-strings/introduction.md b/concepts/verbatim-strings/introduction.md
index 182dd64098..7538524eec 100644
--- a/concepts/verbatim-strings/introduction.md
+++ b/concepts/verbatim-strings/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Verbatim strings allow multi-line strings. They are introduced with an @.
 
 ```csharp
diff --git a/concepts/while-loops/about.md b/concepts/while-loops/about.md
index de700d6af4..5f72747719 100644
--- a/concepts/while-loops/about.md
+++ b/concepts/while-loops/about.md
@@ -1,3 +1,5 @@
+# About
+
 To repeatedly execute logic, one can use loops. One of the most common loop types in C# is the `while` loop, which keeps on looping until a boolean condition evaluates to `false`.
 
 ```csharp
diff --git a/concepts/while-loops/introduction.md b/concepts/while-loops/introduction.md
index 7f7d278c6c..1ca57916e4 100644
--- a/concepts/while-loops/introduction.md
+++ b/concepts/while-loops/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In this exercise you may also want to use a loop. There are several ways to write loops in C#, but the `while` loop is most appropriate here:
 
 ```csharp
diff --git a/docs/ABOUT.md b/docs/ABOUT.md
index 4ba7d04d82..37a039ca5a 100644
--- a/docs/ABOUT.md
+++ b/docs/ABOUT.md
@@ -1,3 +1,5 @@
+# About
+
 C# is a multi-paradigm, statically-typed programming language with object-oriented, declarative, functional, generic, lazy, integrated querying features and type inference. 
 
 __Statically-typed__ means that identifiers have a [type](https://en.wikipedia.org/wiki/Type_system#Static_type_checking) set at compile time--like those in Java, C++ or Haskell--instead of holding data of any type like those in Python, Ruby or JavaScript. 
diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md
index fd3c38f4bd..fe9b80184c 100644
--- a/docs/INSTALLATION.md
+++ b/docs/INSTALLATION.md
@@ -1,3 +1,5 @@
+# Installation
+
 ### Installing .NET Core
 
 The C# track is built on top of the [.NET Core](https://www.microsoft.com/net/core/platform) platform, which runs on Windows, Linux and macOS. To build .NET Core projects, you can use the .NET Core Command Line Interface (CLI). This CLI is part of the .NET Core SDK, which you can install by following the [installation instructions](https://www.microsoft.com/net/download/core). Note: the C# track requires SDK version 3.0 or greater.
diff --git a/docs/LEARNING.md b/docs/LEARNING.md
index 5d84a4a2fd..f179b5290c 100644
--- a/docs/LEARNING.md
+++ b/docs/LEARNING.md
@@ -1,4 +1,4 @@
-## Learning C# 
+# Learning C# 
 
 ### Websites
 
diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md
index 003a8a1eec..0b001f8c77 100644
--- a/docs/RESOURCES.md
+++ b/docs/RESOURCES.md
@@ -1,4 +1,4 @@
-## Recommended Learning Resources
+# Recommended Learning Resources
 
 ### Blogs
 
diff --git a/docs/TESTS.md b/docs/TESTS.md
index 290fb0ff9c..c91be08138 100644
--- a/docs/TESTS.md
+++ b/docs/TESTS.md
@@ -1,3 +1,5 @@
+# Tests
+
 ## Running Tests
 
 To run the tests, execute the following command:
diff --git a/exercises/concept/annalyns-infiltration/.docs/hints.md b/exercises/concept/annalyns-infiltration/.docs/hints.md
index 9e631dd402..a3e8e58d78 100644
--- a/exercises/concept/annalyns-infiltration/.docs/hints.md
+++ b/exercises/concept/annalyns-infiltration/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - There are three [boolean operators][operators] to work with boolean values.
diff --git a/exercises/concept/annalyns-infiltration/.docs/instructions.md b/exercises/concept/annalyns-infiltration/.docs/instructions.md
index 22711a8e42..1416a54cb7 100644
--- a/exercises/concept/annalyns-infiltration/.docs/instructions.md
+++ b/exercises/concept/annalyns-infiltration/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise, you'll be implementing the quest logic for a new RPG game a friend is developing.
 
 The game's main character is Annalyn, a brave girl with a fierce and loyal pet dog. Unfortunately, disaster strikes, as her best friend was kidnapped while searching for berries in the forest.
diff --git a/exercises/concept/annalyns-infiltration/.docs/introduction.md b/exercises/concept/annalyns-infiltration/.docs/introduction.md
index 5341d27350..f41347edbd 100644
--- a/exercises/concept/annalyns-infiltration/.docs/introduction.md
+++ b/exercises/concept/annalyns-infiltration/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Booleans in C# are represented by the `bool` type, which values can be either `true` or `false`.
 
 C# supports three boolean operators: `!` (NOT), `&&` (AND), and `||` (OR).
diff --git a/exercises/concept/annalyns-infiltration/.meta/design.md b/exercises/concept/annalyns-infiltration/.meta/design.md
index 88fc902ed4..490c7e3115 100644
--- a/exercises/concept/annalyns-infiltration/.meta/design.md
+++ b/exercises/concept/annalyns-infiltration/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `bool` type and its two values.
diff --git a/exercises/concept/attack-of-the-trolls/.docs/hints.md b/exercises/concept/attack-of-the-trolls/.docs/hints.md
index e63519bf80..22155fe000 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/hints.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## 1. Get default permissions for an account type
 
 - Define the `Permission` enum with values for the following permission types: `None`, `Read`, `Write` and `Delete`.
diff --git a/exercises/concept/attack-of-the-trolls/.docs/instructions.md b/exercises/concept/attack-of-the-trolls/.docs/instructions.md
index 2cc5ede74f..600bfd5d01 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/instructions.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be checking permissions of user accounts on an internet forum. The forum supports three different permissions:
 
 - Read
diff --git a/exercises/concept/attack-of-the-trolls/.docs/introduction.md b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
index a41e13147a..44a34a1f01 100644
--- a/exercises/concept/attack-of-the-trolls/.docs/introduction.md
+++ b/exercises/concept/attack-of-the-trolls/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Attributes
 
 A [C# `Attribute`](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/) provides a way to decorate a declaration to associate metadata to: a class, a method, an enum, a field, a property or any [other supported](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/#attribute-targets) declarations.
diff --git a/exercises/concept/attack-of-the-trolls/.meta/design.md b/exercises/concept/attack-of-the-trolls/.meta/design.md
index 57feceaee5..3f811aea58 100644
--- a/exercises/concept/attack-of-the-trolls/.meta/design.md
+++ b/exercises/concept/attack-of-the-trolls/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what a flags enumeration is.
diff --git a/exercises/concept/authentication-system/.docs/hints.md b/exercises/concept/authentication-system/.docs/hints.md
index 72d763a713..d9acdb6525 100644
--- a/exercises/concept/authentication-system/.docs/hints.md
+++ b/exercises/concept/authentication-system/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Readonly fields][readonly-fields]: how to define a readonly field.
diff --git a/exercises/concept/authentication-system/.docs/instructions.md b/exercises/concept/authentication-system/.docs/instructions.md
index 2d5d4d2592..8f56a772b6 100644
--- a/exercises/concept/authentication-system/.docs/instructions.md
+++ b/exercises/concept/authentication-system/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 The authentication system that you last saw in (TODO cross-ref-tba) is in need of some attention. You have been tasked with cleaning up the code. Such a cleanup project will not only make life easy for future maintainers but will expose and fix some security vulnerabilities.
 
 ## 1. Set appropriate fields and properties to const
diff --git a/exercises/concept/authentication-system/.docs/introduction.md b/exercises/concept/authentication-system/.docs/introduction.md
index 25ccf76af7..e56b8ae739 100644
--- a/exercises/concept/authentication-system/.docs/introduction.md
+++ b/exercises/concept/authentication-system/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Constants
 
 The `const` modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
diff --git a/exercises/concept/authentication-system/.meta/design.md b/exercises/concept/authentication-system/.meta/design.md
index f8f727edbe..f2d92558bc 100644
--- a/exercises/concept/authentication-system/.meta/design.md
+++ b/exercises/concept/authentication-system/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to define `const` values.
diff --git a/exercises/concept/beauty-salon-goes-global/.docs/hints.md b/exercises/concept/beauty-salon-goes-global/.docs/hints.md
index 6a20856000..29842cda58 100644
--- a/exercises/concept/beauty-salon-goes-global/.docs/hints.md
+++ b/exercises/concept/beauty-salon-goes-global/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - This [article][time-overview] is an overview of dates, times and time zones on .NET.
diff --git a/exercises/concept/beauty-salon-goes-global/.docs/instructions.md b/exercises/concept/beauty-salon-goes-global/.docs/instructions.md
index 43e1c02b5c..5e1d669180 100644
--- a/exercises/concept/beauty-salon-goes-global/.docs/instructions.md
+++ b/exercises/concept/beauty-salon-goes-global/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you are back in the world of salons (first introduced in the `datetimes` exercise). As with a number of your projects another of your clients has had great success and opened outlets in London and Paris in addition to their New York base.
 
 ## 1. Provide local time equivalents of UTC (Universal Coordinated Time) appointments for the administrators
diff --git a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
index b3cc1dbcf6..64b1849717 100644
--- a/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
+++ b/exercises/concept/beauty-salon-goes-global/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Time
 
 The concept of _time_ is dealt with in .NET using the `DateTime` struct. There are routines to convert between local time and UTC. Arithmetic can be performed with the help of `TimeSpan`.
diff --git a/exercises/concept/beauty-salon-goes-global/.meta/design.md b/exercises/concept/beauty-salon-goes-global/.meta/design.md
index fddca26362..c5a30dcb46 100644
--- a/exercises/concept/beauty-salon-goes-global/.meta/design.md
+++ b/exercises/concept/beauty-salon-goes-global/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to use `time` in C#.
diff --git a/exercises/concept/bird-watcher/.docs/hints.md b/exercises/concept/bird-watcher/.docs/hints.md
index 9c9cc3280e..859b07c1e5 100644
--- a/exercises/concept/bird-watcher/.docs/hints.md
+++ b/exercises/concept/bird-watcher/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - The bird count per day is stored in a [field][fields] named `birdsPerDay`.
diff --git a/exercises/concept/bird-watcher/.docs/instructions.md b/exercises/concept/bird-watcher/.docs/instructions.md
index c7946b8f79..3356757f10 100644
--- a/exercises/concept/bird-watcher/.docs/instructions.md
+++ b/exercises/concept/bird-watcher/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You're an avid bird watcher that keeps track of how many birds have visited your garden in the last seven days.
 
 You have six tasks, all dealing with the numbers of birds that visited your garden.
diff --git a/exercises/concept/bird-watcher/.docs/introduction.md b/exercises/concept/bird-watcher/.docs/introduction.md
index 95142f5c7e..5d1e4ee4de 100644
--- a/exercises/concept/bird-watcher/.docs/introduction.md
+++ b/exercises/concept/bird-watcher/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Arrays
 
 In C#, data structures that can hold zero or more elements are known as _collections_. An **array** is a collection that has a fixed size/length and whose elements must all be of the same type. Elements can be assigned to an array or retrieved from it using an index. C# arrays are zero-based, meaning that the first element's index is always zero:
diff --git a/exercises/concept/bird-watcher/.meta/design.md b/exercises/concept/bird-watcher/.meta/design.md
index a41caebea1..3fd9708152 100644
--- a/exercises/concept/bird-watcher/.meta/design.md
+++ b/exercises/concept/bird-watcher/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 Of the many available C# collection types, we chose to use the `array` collection type as the first collection type students will be taught for the following reasons:
 
 - Arrays don't require the student to know about generics.
diff --git a/exercises/concept/booking-up-for-beauty/.docs/hints.md b/exercises/concept/booking-up-for-beauty/.docs/hints.md
index 4209ebd50c..f730addff4 100644
--- a/exercises/concept/booking-up-for-beauty/.docs/hints.md
+++ b/exercises/concept/booking-up-for-beauty/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Tutorial on dates and time by csharp.net][csharp.net-datetimes-working-with-datetimes-time]
diff --git a/exercises/concept/booking-up-for-beauty/.docs/instructions.md b/exercises/concept/booking-up-for-beauty/.docs/instructions.md
index 929d126754..3bc9da2f7a 100644
--- a/exercises/concept/booking-up-for-beauty/.docs/instructions.md
+++ b/exercises/concept/booking-up-for-beauty/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be working on an appointment scheduler for a beauty salon in New York that opened on September 15th in 2012.
 
 You have four tasks, which will all involve appointment dates. The dates and times will use one of the following three formats:
diff --git a/exercises/concept/booking-up-for-beauty/.docs/introduction.md b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
index 7ba7a7786f..20e7d625b9 100644
--- a/exercises/concept/booking-up-for-beauty/.docs/introduction.md
+++ b/exercises/concept/booking-up-for-beauty/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A `DateTime` in C# is an immutable object that contains both date _and_ time information. `DateTime` instances are manipulated by calling their methods. Once a `DateTime` has been constructed, its value can never change. Any methods that appear to modify a `DateTime` will actually return a new `DateTime`.
 
 The textual representation of dates and times is dependent on the _culture_. Consider a `DateTime` with its date set to March 28 2019 and its time set to 14:30:59. Converting this `DateTime` to a `string` when using the `en-US` culture (American English) returns `"3/28/19 2:30:59 PM"`. When using the `fr-BE` culture (Belgian French), the same code returns a different value: `"28/03/19 14:30:59"`.
diff --git a/exercises/concept/booking-up-for-beauty/.meta/design.md b/exercises/concept/booking-up-for-beauty/.meta/design.md
index b85d0a8a2d..57d4841971 100644
--- a/exercises/concept/booking-up-for-beauty/.meta/design.md
+++ b/exercises/concept/booking-up-for-beauty/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `DateTime` type.
diff --git a/exercises/concept/building-telemetry/.docs/hints.md b/exercises/concept/building-telemetry/.docs/hints.md
index 910df616a9..ed9f18c383 100644
--- a/exercises/concept/building-telemetry/.docs/hints.md
+++ b/exercises/concept/building-telemetry/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [passing-parameters][passing-parameters]: explains how values can be passed as arguments.
diff --git a/exercises/concept/building-telemetry/.docs/instructions.md b/exercises/concept/building-telemetry/.docs/instructions.md
index 0f6ec12358..7543a43ae0 100644
--- a/exercises/concept/building-telemetry/.docs/instructions.md
+++ b/exercises/concept/building-telemetry/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 The remote control car project you kicked off in the `classes` exercise has gone well (congratulations!) and due to a number of recent sponsorship deals there is money in the budget for enhancements.
 
 Part of the budget is being used to provide some telemetry.
diff --git a/exercises/concept/building-telemetry/.docs/introduction.md b/exercises/concept/building-telemetry/.docs/introduction.md
index 1c42283f86..37f6df92f1 100644
--- a/exercises/concept/building-telemetry/.docs/introduction.md
+++ b/exercises/concept/building-telemetry/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 This exercise discusses some details of method parameters and their use in C#.
 
 Parameters convey information from a calling method to a called method.
diff --git a/exercises/concept/building-telemetry/.meta/design.md b/exercises/concept/building-telemetry/.meta/design.md
index b7d66b24c1..e5155adbae 100644
--- a/exercises/concept/building-telemetry/.meta/design.md
+++ b/exercises/concept/building-telemetry/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know the difference between value and reference type parameters.
diff --git a/exercises/concept/calculator-conundrum/.docs/hints.md b/exercises/concept/calculator-conundrum/.docs/hints.md
index e69de29bb2..93c36d9988 100644
--- a/exercises/concept/calculator-conundrum/.docs/hints.md
+++ b/exercises/concept/calculator-conundrum/.docs/hints.md
@@ -0,0 +1,2 @@
+# Hints
+
diff --git a/exercises/concept/calculator-conundrum/.docs/instructions.md b/exercises/concept/calculator-conundrum/.docs/instructions.md
index e6712b24fa..eb252f4ca8 100644
--- a/exercises/concept/calculator-conundrum/.docs/instructions.md
+++ b/exercises/concept/calculator-conundrum/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you will be building error handling for a simple integer calculator. To make matters simple, methods for calculating addition, multiplication and division are provided.
 
 The goal is to have a working calculator that returns a string with the following pattern: `16 + 51 = 67`, when provided with arguments `16`, `51` and `+`.
diff --git a/exercises/concept/calculator-conundrum/.docs/introduction.md b/exercises/concept/calculator-conundrum/.docs/introduction.md
index 002ea03980..effb2cf38c 100644
--- a/exercises/concept/calculator-conundrum/.docs/introduction.md
+++ b/exercises/concept/calculator-conundrum/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Exceptions in C# provide a structured, uniform, and type-safe way of handling error conditions that occur during runtime. Proper handling of exceptions and error is important when trying to prevent application crashes.
 
 In C#, all exceptions have `System.Exception` class as their base type. It contains important properties such as `Message`, which contains a human-readable description of the reason for the exception being thrown.
diff --git a/exercises/concept/calculator-conundrum/.meta/design.md b/exercises/concept/calculator-conundrum/.meta/design.md
index 3f6256dd9b..40b6f70d94 100644
--- a/exercises/concept/calculator-conundrum/.meta/design.md
+++ b/exercises/concept/calculator-conundrum/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Goal
 
 The goal of this exercise is to teach the student the Concept of Exceptions in C#.
diff --git a/exercises/concept/cars-assemble/.docs/hints.md b/exercises/concept/cars-assemble/.docs/hints.md
index 2c7decd6b3..15caccb0fc 100644
--- a/exercises/concept/cars-assemble/.docs/hints.md
+++ b/exercises/concept/cars-assemble/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Numbers tutorial][numbers].
diff --git a/exercises/concept/cars-assemble/.docs/instructions.md b/exercises/concept/cars-assemble/.docs/instructions.md
index e539f6fbc9..b948354806 100644
--- a/exercises/concept/cars-assemble/.docs/instructions.md
+++ b/exercises/concept/cars-assemble/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be writing code to analyze the production of an assembly line in a car factory. The assembly line's speed can range from `0` (off) to `10` (maximum).
 
 At its lowest speed (`1`), `221` cars are produced each hour. The production increases linearly with the speed. So with the speed set to `4`, it should produce `4 * 221 = 884` cars per hour. However, higher speeds increase the likelihood that faulty cars are produced, which then have to be discarded. The following table shows how speed influences the success rate:
diff --git a/exercises/concept/cars-assemble/.docs/introduction.md b/exercises/concept/cars-assemble/.docs/introduction.md
index 69949b8590..0d259919e0 100644
--- a/exercises/concept/cars-assemble/.docs/introduction.md
+++ b/exercises/concept/cars-assemble/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Numbers
 
 There are two different types of numbers in C#:
diff --git a/exercises/concept/cars-assemble/.meta/design.md b/exercises/concept/cars-assemble/.meta/design.md
index 0c20b2d46c..43a171cbe0 100644
--- a/exercises/concept/cars-assemble/.meta/design.md
+++ b/exercises/concept/cars-assemble/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the two most commonly used number types, `int` and `double`.
diff --git a/exercises/concept/developer-privileges/.docs/hints.md b/exercises/concept/developer-privileges/.docs/hints.md
index bafc7d1cc9..67f6ad623f 100644
--- a/exercises/concept/developer-privileges/.docs/hints.md
+++ b/exercises/concept/developer-privileges/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [object initializer][object-initializers] documentation describes how to use initializers.
diff --git a/exercises/concept/developer-privileges/.docs/instructions.md b/exercises/concept/developer-privileges/.docs/instructions.md
index 3d9dfed23a..85d5e432cc 100644
--- a/exercises/concept/developer-privileges/.docs/instructions.md
+++ b/exercises/concept/developer-privileges/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You've been asked to do some more work on the network authentication system.
 
 In addition to the admin identity being hard-coded in the system during development the powers that be also want senior developers to be given the same treatment.
diff --git a/exercises/concept/developer-privileges/.docs/introduction.md b/exercises/concept/developer-privileges/.docs/introduction.md
index 25b3b07ef5..b9d21b15df 100644
--- a/exercises/concept/developer-privileges/.docs/introduction.md
+++ b/exercises/concept/developer-privileges/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Object initializers are an alternative to constructors. The syntax is illustrated below. You provide a comma separated list of name-value pairs separated with `=` within curly brackets:
 
 ```csharp
diff --git a/exercises/concept/developer-privileges/.meta/design.md b/exercises/concept/developer-privileges/.meta/design.md
index ab869b6561..166dc267f6 100644
--- a/exercises/concept/developer-privileges/.meta/design.md
+++ b/exercises/concept/developer-privileges/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how and when to user object initializers.
diff --git a/exercises/concept/elons-toys/.docs/hints.md b/exercises/concept/elons-toys/.docs/hints.md
index a63d6f70d0..a57161fb77 100644
--- a/exercises/concept/elons-toys/.docs/hints.md
+++ b/exercises/concept/elons-toys/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 ## 1. Buy a brand-new remote controlled car
diff --git a/exercises/concept/elons-toys/.docs/instructions.md b/exercises/concept/elons-toys/.docs/instructions.md
index 1d57a5ba6b..faf855783e 100644
--- a/exercises/concept/elons-toys/.docs/instructions.md
+++ b/exercises/concept/elons-toys/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be playing around with a remote controlled car, which you've finally saved enough money for to buy.
 
 Cars start with full (100%) batteries. Each time you drive the car using the remote control, it covers 20 meters and drains one percent of the battery.
diff --git a/exercises/concept/elons-toys/.docs/introduction.md b/exercises/concept/elons-toys/.docs/introduction.md
index e3770a9229..bd1f6552d8 100644
--- a/exercises/concept/elons-toys/.docs/introduction.md
+++ b/exercises/concept/elons-toys/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The primary object-oriented construct in C# is the _class_, which is a combination of data (_fields_) and behavior (_methods_). The fields and methods of a class are known as its _members_.
 
 Access to members can be restricted through access modifiers, the two most common ones being:
diff --git a/exercises/concept/elons-toys/.meta/design.md b/exercises/concept/elons-toys/.meta/design.md
index ff712986a7..7ef32bd91d 100644
--- a/exercises/concept/elons-toys/.meta/design.md
+++ b/exercises/concept/elons-toys/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what classes are.
diff --git a/exercises/concept/faceid-2/.docs/hints.md b/exercises/concept/faceid-2/.docs/hints.md
index 538635cf70..023d4a2f00 100644
--- a/exercises/concept/faceid-2/.docs/hints.md
+++ b/exercises/concept/faceid-2/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ### General
 
 - [Equality][equality]: how equality comparisons work in C#, including reference- and value type equality.
diff --git a/exercises/concept/faceid-2/.docs/instructions.md b/exercises/concept/faceid-2/.docs/instructions.md
index 24aa084feb..7d6f725a67 100644
--- a/exercises/concept/faceid-2/.docs/instructions.md
+++ b/exercises/concept/faceid-2/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You are working on a system to simplify the login process for your organization's network. The tasks concern the authentication part. The system uses facial recognition to prove identity.
 
 In all occurrences the eye color parameter is guaranteed to be non-null.
diff --git a/exercises/concept/faceid-2/.docs/introduction.md b/exercises/concept/faceid-2/.docs/introduction.md
index b6353dab95..a48a293ad7 100644
--- a/exercises/concept/faceid-2/.docs/introduction.md
+++ b/exercises/concept/faceid-2/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Equality
 
 Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`.
diff --git a/exercises/concept/faceid-2/.meta/design.md b/exercises/concept/faceid-2/.meta/design.md
index b037290b70..db293e3037 100644
--- a/exercises/concept/faceid-2/.meta/design.md
+++ b/exercises/concept/faceid-2/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to check for equality and inequality.
diff --git a/exercises/concept/football-match-reports/.docs/hints.md b/exercises/concept/football-match-reports/.docs/hints.md
index a5703ec31d..7d635ece83 100644
--- a/exercises/concept/football-match-reports/.docs/hints.md
+++ b/exercises/concept/football-match-reports/.docs/hints.md
@@ -1,4 +1,4 @@
-## General
+# General
 
 [switch statement][switch-statement] documentation provides an introduction to `switch` statements.
 
diff --git a/exercises/concept/football-match-reports/.docs/instructions.md b/exercises/concept/football-match-reports/.docs/instructions.md
index d34452f5e6..6bacd19e38 100644
--- a/exercises/concept/football-match-reports/.docs/instructions.md
+++ b/exercises/concept/football-match-reports/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You are developing a system to help the staff of a football/soccer club's web site report on matches. Data is received from a variety of sources and piped into a single stream after being cleaned up.
 
 ### 1. Output descriptions of the players based on their shirt number
diff --git a/exercises/concept/football-match-reports/.docs/introduction.md b/exercises/concept/football-match-reports/.docs/introduction.md
index 8395a6f1c9..dc4cf3c75a 100644
--- a/exercises/concept/football-match-reports/.docs/introduction.md
+++ b/exercises/concept/football-match-reports/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Wikipedia describes a `switch` statement as "a type of selection control mechanism used to allow the value of a variable or expression to change the control flow of program".
 
 The mechanism involves the following keywords: `switch`, `case`, `break` and `default`.
diff --git a/exercises/concept/football-match-reports/.meta/design.md b/exercises/concept/football-match-reports/.meta/design.md
index f26dbe90a8..2fa55983e6 100644
--- a/exercises/concept/football-match-reports/.meta/design.md
+++ b/exercises/concept/football-match-reports/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to use simple `switch` statements.
diff --git a/exercises/concept/high-school-sweethearts/.docs/hints.md b/exercises/concept/high-school-sweethearts/.docs/hints.md
index 9c933944ed..12322683c5 100644
--- a/exercises/concept/high-school-sweethearts/.docs/hints.md
+++ b/exercises/concept/high-school-sweethearts/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [String interpolation][string-interpolation]: tutorial on how to use string interpolation.
diff --git a/exercises/concept/high-school-sweethearts/.docs/instructions.md b/exercises/concept/high-school-sweethearts/.docs/instructions.md
index 0b2fa4867f..d0e6877a15 100644
--- a/exercises/concept/high-school-sweethearts/.docs/instructions.md
+++ b/exercises/concept/high-school-sweethearts/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise, you are going to help high school sweethearts profess their love on social media.
 
 ## 1. Display the couple's name separated by a heart
diff --git a/exercises/concept/high-school-sweethearts/.docs/introduction.md b/exercises/concept/high-school-sweethearts/.docs/introduction.md
index ca33e2d711..b53262dec8 100644
--- a/exercises/concept/high-school-sweethearts/.docs/introduction.md
+++ b/exercises/concept/high-school-sweethearts/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## String Formatting
 
 There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation.
diff --git a/exercises/concept/high-school-sweethearts/.meta/design.md b/exercises/concept/high-school-sweethearts/.meta/design.md
index afbfaf4977..4814d841e2 100644
--- a/exercises/concept/high-school-sweethearts/.meta/design.md
+++ b/exercises/concept/high-school-sweethearts/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to use the `ToString()` method to convert any object to a `string`.
diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/hints.md b/exercises/concept/hyper-optimized-telemetry/.docs/hints.md
index 80779bd650..53cd762e56 100644
--- a/exercises/concept/hyper-optimized-telemetry/.docs/hints.md
+++ b/exercises/concept/hyper-optimized-telemetry/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Integral numeric types][integral-numeric-types]: overview of the integral numeric types.
diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/instructions.md b/exercises/concept/hyper-optimized-telemetry/.docs/instructions.md
index ec485ae40c..4e083477e3 100644
--- a/exercises/concept/hyper-optimized-telemetry/.docs/instructions.md
+++ b/exercises/concept/hyper-optimized-telemetry/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Work continues on the remote control car project. Bandwidth in the telemetry system is at a premium and you have been asked to implement a message protocol for communicating telemetry data.
 
 Data is transmitted in a buffer (byte array). When integers are sent, the size of the buffer is reduced by employing the protocol described below.
diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
index a134fd0930..714616a7a8 100644
--- a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
+++ b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C#, like many statically typed languages, provides a number of types that represent integers, each with its own range of values. At the low end, the `sbyte` type has a minimum value of -128 and a maximum value of 127. Like all the integer types these values are available as `.MinValue` and `.MaxValue`. At the high end, the `long` type has a minimum value of -9,223,372,036,854,775,808 and a maximum value of 9,223,372,036,854,775,807. In between lie the `short` and `int` types.
 
 The ranges are determined by the storage width of the type as allocated by the system. For example, a `byte` uses 8 bits and a `long` uses 64 bits.
diff --git a/exercises/concept/hyper-optimized-telemetry/.meta/design.md b/exercises/concept/hyper-optimized-telemetry/.meta/design.md
index 43aae5b88f..2f3133c2e1 100644
--- a/exercises/concept/hyper-optimized-telemetry/.meta/design.md
+++ b/exercises/concept/hyper-optimized-telemetry/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the difference between signed and unsigned integral types.
diff --git a/exercises/concept/hyperia-forex/.docs/hints.md b/exercises/concept/hyperia-forex/.docs/hints.md
index 7f9f1b6615..d12fd4e3d9 100644
--- a/exercises/concept/hyperia-forex/.docs/hints.md
+++ b/exercises/concept/hyperia-forex/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - This documentation of [operator overloading][operator-overloading] details the syntax.
diff --git a/exercises/concept/hyperia-forex/.docs/instructions.md b/exercises/concept/hyperia-forex/.docs/instructions.md
index 3f214ecc4b..dbaf262288 100644
--- a/exercises/concept/hyperia-forex/.docs/instructions.md
+++ b/exercises/concept/hyperia-forex/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You've been tempted back to Hyperia (with the high inflation) for an eye watering daily rate.
 
 The Central Bank is contemplating introducing the US Dollar as a second currency so all the accounting systems have to be adapted to handle multiple currencies.
diff --git a/exercises/concept/hyperia-forex/.docs/introduction.md b/exercises/concept/hyperia-forex/.docs/introduction.md
index 9c72dea800..c570dd8524 100644
--- a/exercises/concept/hyperia-forex/.docs/introduction.md
+++ b/exercises/concept/hyperia-forex/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The principal arithmetic and comparison operators can be adapted for use by your own classes and structs. This is known as _operator overloading_.
 
 Most operators have the form:
diff --git a/exercises/concept/hyperia-forex/.meta/design.md b/exercises/concept/hyperia-forex/.meta/design.md
index 4d50b37c78..45676a2c94 100644
--- a/exercises/concept/hyperia-forex/.meta/design.md
+++ b/exercises/concept/hyperia-forex/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how and why to use standard C# operators in your own classes
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md
index 3ae80c9f40..9eddf4df27 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md
+++ b/exercises/concept/hyperinflation-hits-hyperia/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## 1. Print bank note denominations
 
 - [Integral numeric types][integral-numeric-types]: overview of the integral numeric types.
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md
index 8026124c0e..be30d672a9 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md
+++ b/exercises/concept/hyperinflation-hits-hyperia/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 The country of Hyperia has its problems. In particular, inflation is out of control. You have been flown in to take up a contract at the central bank.
 
 ## 1. Print bank note denominations
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
index a2313bf95e..20480ae5df 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
+++ b/exercises/concept/hyperinflation-hits-hyperia/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Arithmetic overflow occurs when a computation such as an arithmetic operation or type conversion results in a value that is greater than the capacity of the receiving type.
 
 Expressions of type `int` and `long` and their unsigned counterparts will quietly wrap around under these circumstances.
diff --git a/exercises/concept/hyperinflation-hits-hyperia/.meta/design.md b/exercises/concept/hyperinflation-hits-hyperia/.meta/design.md
index b1f100a0fe..0bf0c5fb3f 100644
--- a/exercises/concept/hyperinflation-hits-hyperia/.meta/design.md
+++ b/exercises/concept/hyperinflation-hits-hyperia/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Explain integral number overflows.
diff --git a/exercises/concept/instruments-of-texas/.docs/hints.md b/exercises/concept/instruments-of-texas/.docs/hints.md
index 47da3a1127..7033e5c9ba 100644
--- a/exercises/concept/instruments-of-texas/.docs/hints.md
+++ b/exercises/concept/instruments-of-texas/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Create user-defined exceptions][create-user-defined-exceptions]: how to create user-defined exceptions
diff --git a/exercises/concept/instruments-of-texas/.docs/instructions.md b/exercises/concept/instruments-of-texas/.docs/instructions.md
index efd11c69ff..d22d43b9b2 100644
--- a/exercises/concept/instruments-of-texas/.docs/instructions.md
+++ b/exercises/concept/instruments-of-texas/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 While working at _Instruments of Texas_, you are tasked to work on an experimental calculator written in C#. You are building a test harness to verify a number of calculator functions starting with multiplication. You will see that there is particular concern when the two operands of the multiplication are negative.
 
 The `Calculator` class has been provided for you and should not be modified.
diff --git a/exercises/concept/instruments-of-texas/.docs/introduction.md b/exercises/concept/instruments-of-texas/.docs/introduction.md
index 263dee13d5..40076020f6 100644
--- a/exercises/concept/instruments-of-texas/.docs/introduction.md
+++ b/exercises/concept/instruments-of-texas/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## User Defined Exceptions
 
 A user-defined exception is any class defined in your code that is derived from `System.Exception`. It is subject to all the rules of class inheritance but in addition the compiler and language runtime treat such classes in a special way allowing their instances to be thrown and caught outside the normal control flow as discussed in the `exceptions` exercise.
diff --git a/exercises/concept/instruments-of-texas/.meta/design.md b/exercises/concept/instruments-of-texas/.meta/design.md
index d3ea066947..c1dc181a64 100644
--- a/exercises/concept/instruments-of-texas/.meta/design.md
+++ b/exercises/concept/instruments-of-texas/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to define a user-defined exception.
diff --git a/exercises/concept/interest-is-interesting/.docs/hints.md b/exercises/concept/interest-is-interesting/.docs/hints.md
index fa59d9f52b..a55a4608e8 100644
--- a/exercises/concept/interest-is-interesting/.docs/hints.md
+++ b/exercises/concept/interest-is-interesting/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Floating-point numeric types introduction][docs.microsoft.com-floating_point_numeric_types].
diff --git a/exercises/concept/interest-is-interesting/.docs/instructions.md b/exercises/concept/interest-is-interesting/.docs/instructions.md
index 0f32d3ef04..535035c109 100644
--- a/exercises/concept/interest-is-interesting/.docs/instructions.md
+++ b/exercises/concept/interest-is-interesting/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be working with savings accounts. Each year, the balance of your savings account is updated based on its interest rate. The interest rate your bank gives you depends on the amount of money in your account (its balance):
 
 - -3.213% for a negative balance.
diff --git a/exercises/concept/interest-is-interesting/.docs/introduction.md b/exercises/concept/interest-is-interesting/.docs/introduction.md
index cfde2d2adc..ec9762a818 100644
--- a/exercises/concept/interest-is-interesting/.docs/introduction.md
+++ b/exercises/concept/interest-is-interesting/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Floating Point Numbers
 
 A floating-point number is a number with zero or more digits behind the decimal separator. Examples are `-2.4`, `0.1`, `3.14`, `16.984025` and `1024.0`.
diff --git a/exercises/concept/interest-is-interesting/.meta/design.md b/exercises/concept/interest-is-interesting/.meta/design.md
index 9ecb39352b..8eb415c6ec 100644
--- a/exercises/concept/interest-is-interesting/.meta/design.md
+++ b/exercises/concept/interest-is-interesting/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the three floating point types: `double`, `float` and `decimal`.
diff --git a/exercises/concept/international-calling-connoisseur/.docs/hints.md b/exercises/concept/international-calling-connoisseur/.docs/hints.md
index 4b470880a4..bf75d75a1b 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/hints.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ### 1. Create a new dictionary
 
 A dictionary is like any other class. You simply 'new' it to create an empty instance.
diff --git a/exercises/concept/international-calling-connoisseur/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
index dbbb1347ce..346a15a185 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/instructions.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be writing code to keep track of international dialling codes via an international dialing code dictionary.
 
 The dictionary uses an integer for its keys (the dialing code) and a string (country name) for its values.
diff --git a/exercises/concept/international-calling-connoisseur/.docs/introduction.md b/exercises/concept/international-calling-connoisseur/.docs/introduction.md
index 91a2a23020..ecbc0f2a27 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/introduction.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A dictionary is a collection of elements where each element comprises a key and value such that if a key is passed to a method of the dictionary its associated value is returned. It has the same role as maps or associative arrays do in other languages.
 
 A dictionary can be created as follows:
diff --git a/exercises/concept/international-calling-connoisseur/.meta/design.md b/exercises/concept/international-calling-connoisseur/.meta/design.md
index fa9a712e7f..75c4555dee 100644
--- a/exercises/concept/international-calling-connoisseur/.meta/design.md
+++ b/exercises/concept/international-calling-connoisseur/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `Dictionary` type.
diff --git a/exercises/concept/land-grab-in-space/.docs/hints.md b/exercises/concept/land-grab-in-space/.docs/hints.md
index 250e8458e8..2dbb9d0b89 100644
--- a/exercises/concept/land-grab-in-space/.docs/hints.md
+++ b/exercises/concept/land-grab-in-space/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [structs][structs]: introduction to structs.
diff --git a/exercises/concept/land-grab-in-space/.docs/instructions.md b/exercises/concept/land-grab-in-space/.docs/instructions.md
index cd1152a9e2..89e04a7b3e 100644
--- a/exercises/concept/land-grab-in-space/.docs/instructions.md
+++ b/exercises/concept/land-grab-in-space/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You have been tasked by the claims department of Isaacs Asteroid Exploration Co. to improve the performance of their land claim system.
 
 Every time a new asteroid is ready for exploitation speculators are invited to stake their claim to a plot of land. The asteroid's land is divided into 4 sided plots. Speculators claim the land by specifying its dimensions.
diff --git a/exercises/concept/land-grab-in-space/.docs/introduction.md b/exercises/concept/land-grab-in-space/.docs/introduction.md
index 6b1142d00f..d131de15d0 100644
--- a/exercises/concept/land-grab-in-space/.docs/introduction.md
+++ b/exercises/concept/land-grab-in-space/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# `struct`s are closely related `class`s. They have state and behavior. They have constructors that take arguments, instances can be assigned, tested for equality and stored in collections.
 
 ```csharp
diff --git a/exercises/concept/land-grab-in-space/.meta/design.md b/exercises/concept/land-grab-in-space/.meta/design.md
index ca0f836330..3c4e6318c9 100644
--- a/exercises/concept/land-grab-in-space/.meta/design.md
+++ b/exercises/concept/land-grab-in-space/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what structs are.
diff --git a/exercises/concept/log-levels/.docs/hints.md b/exercises/concept/log-levels/.docs/hints.md
index 4ab8ad369a..1b0491f9cb 100644
--- a/exercises/concept/log-levels/.docs/hints.md
+++ b/exercises/concept/log-levels/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - The [csharp.net strings tutorial][tutorial-csharp.net-strings] has a nice introduction to C# `string`s.
diff --git a/exercises/concept/log-levels/.docs/instructions.md b/exercises/concept/log-levels/.docs/instructions.md
index d8a68cf1c2..87efb784ea 100644
--- a/exercises/concept/log-levels/.docs/instructions.md
+++ b/exercises/concept/log-levels/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be processing log-lines.
 
 Each log line is a string formatted as follows: `"[]: "`.
diff --git a/exercises/concept/log-levels/.docs/introduction.md b/exercises/concept/log-levels/.docs/introduction.md
index d7d72cd2ec..3ea1d806cb 100644
--- a/exercises/concept/log-levels/.docs/introduction.md
+++ b/exercises/concept/log-levels/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A `string` in C# is an object that represents immutable text as a sequence of Unicode characters (letters, digits, punctuation, etc.). Double quotes are used to define a `string` instance:
 
 ```csharp
diff --git a/exercises/concept/log-levels/.meta/design.md b/exercises/concept/log-levels/.meta/design.md
index fe18990027..f9f49c3d4d 100644
--- a/exercises/concept/log-levels/.meta/design.md
+++ b/exercises/concept/log-levels/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `string` type.
diff --git a/exercises/concept/logs-logs-logs/.docs/hints.md b/exercises/concept/logs-logs-logs/.docs/hints.md
index 314a70478c..cc3d4b1a3f 100644
--- a/exercises/concept/logs-logs-logs/.docs/hints.md
+++ b/exercises/concept/logs-logs-logs/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Tutorial on working with enums][docs.microsoft.com-enumeration-types].
diff --git a/exercises/concept/logs-logs-logs/.docs/instructions.md b/exercises/concept/logs-logs-logs/.docs/instructions.md
index 4ca2a0a0a5..5093f117ce 100644
--- a/exercises/concept/logs-logs-logs/.docs/instructions.md
+++ b/exercises/concept/logs-logs-logs/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be processing log-lines.
 
 Each log line is a string formatted as follows: `"[]: "`.
diff --git a/exercises/concept/logs-logs-logs/.docs/introduction.md b/exercises/concept/logs-logs-logs/.docs/introduction.md
index 9f383a26bb..1199eb6983 100644
--- a/exercises/concept/logs-logs-logs/.docs/introduction.md
+++ b/exercises/concept/logs-logs-logs/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 The C# `enum` type represents a fixed set of named constants (an enumeration). Its chief purpose is to provide a type-safe way of interacting with numeric constants, limiting the available values to a pre-defined set. A simple enum can be defined as follows:
 
 ```csharp
diff --git a/exercises/concept/logs-logs-logs/.meta/design.md b/exercises/concept/logs-logs-logs/.meta/design.md
index b14f9e187f..0139f07058 100644
--- a/exercises/concept/logs-logs-logs/.meta/design.md
+++ b/exercises/concept/logs-logs-logs/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 After completing this exercise, the student should:
diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/hints.md b/exercises/concept/lucians-luscious-lasagna/.docs/hints.md
index e99d482a2a..9bb6ed8d7b 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/hints.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - An [integer value][integers] can be defined as one or more consecutive digits.
diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md b/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
index a97d3450cf..635a628ce6 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Lucian's girlfriend is on her way home and he hasn't cooked their anniversary dinner!
 
 In this exercise, you're going to write some code to help Lucian cook an exquisite lasagna from his favorite cook book.
diff --git a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
index a0da40de82..10a7abb2be 100644
--- a/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
+++ b/exercises/concept/lucians-luscious-lasagna/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# is a statically-typed language, which means that everything has a type at compile-time. Assigning a value to a name is referred to as defining a variable. A variable can be defined either by explicitly specifying its type, or by letting the C# compiler infer its type based on the assigned value (known as _type inference_). Therefore, the following two variable definitions are equivalent:
 
 ```csharp
diff --git a/exercises/concept/lucians-luscious-lasagna/.meta/design.md b/exercises/concept/lucians-luscious-lasagna/.meta/design.md
index 1247b30df9..b3c21bc74c 100644
--- a/exercises/concept/lucians-luscious-lasagna/.meta/design.md
+++ b/exercises/concept/lucians-luscious-lasagna/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what a variable is
diff --git a/exercises/concept/need-for-speed/.docs/hints.md b/exercises/concept/need-for-speed/.docs/hints.md
index 1c32c838f1..6dc5a222ce 100644
--- a/exercises/concept/need-for-speed/.docs/hints.md
+++ b/exercises/concept/need-for-speed/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## 1. Creating a remote controlled car
 
 - [Define a constructor][constructor-syntax] that has two `int` parameters.
diff --git a/exercises/concept/need-for-speed/.docs/instructions.md b/exercises/concept/need-for-speed/.docs/instructions.md
index 6c495a5750..0c501dad29 100644
--- a/exercises/concept/need-for-speed/.docs/instructions.md
+++ b/exercises/concept/need-for-speed/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be organizing races between various types of remote controlled cars. Each car has its own speed and battery drain characteristics.
 
 Cars start with full (100%) batteries. Each time you drive the car using the remote control, it covers the car's speed in meters and decreases the remaining battery percentage by its battery drain.
diff --git a/exercises/concept/need-for-speed/.docs/introduction.md b/exercises/concept/need-for-speed/.docs/introduction.md
index 1fbd17c9ef..ae9a354400 100644
--- a/exercises/concept/need-for-speed/.docs/introduction.md
+++ b/exercises/concept/need-for-speed/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Creating an instance of a _class_ is done by calling its _constructor_ through the `new` operator. A constructor is a special type of method whose goal is to initialize a newly created instance. Constructors look like regular methods, but without a return type and with a name that matches the classes' name.
 
 ```csharp
diff --git a/exercises/concept/need-for-speed/.meta/design.md b/exercises/concept/need-for-speed/.meta/design.md
index 375174e3cc..b208d4ef9b 100644
--- a/exercises/concept/need-for-speed/.meta/design.md
+++ b/exercises/concept/need-for-speed/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what constructors are
diff --git a/exercises/concept/object-relational-mapping/.docs/hints.md b/exercises/concept/object-relational-mapping/.docs/hints.md
index d291934fe0..8c6d0db463 100644
--- a/exercises/concept/object-relational-mapping/.docs/hints.md
+++ b/exercises/concept/object-relational-mapping/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 Documentation related to `IDisposable` is [here][idisposable]
diff --git a/exercises/concept/object-relational-mapping/.docs/instructions.md b/exercises/concept/object-relational-mapping/.docs/instructions.md
index e6581a9fb1..e06edbaa81 100644
--- a/exercises/concept/object-relational-mapping/.docs/instructions.md
+++ b/exercises/concept/object-relational-mapping/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You are implementing an ORM (Object Relational Mapping) system over a database which has been provided by another team.
 
 The database is capable of handling a single transaction at one time.
diff --git a/exercises/concept/object-relational-mapping/.docs/introduction.md b/exercises/concept/object-relational-mapping/.docs/introduction.md
index ffeafbf696..8d01e3c6f6 100644
--- a/exercises/concept/object-relational-mapping/.docs/introduction.md
+++ b/exercises/concept/object-relational-mapping/.docs/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 If a class implements the `IDisposable` interface then its `Dispose()` method must be called whenever an instance is no longer required. This is typically done from a `catch` or `finally` clause or from the `Dispose()` routine of some caller. `Dispose()` provides an opportunity for unmanaged resources such as operating system objects (which are not managed by the .NET runtime) to be released and the internal state of managed resources to be reset.
diff --git a/exercises/concept/object-relational-mapping/.meta/design.md b/exercises/concept/object-relational-mapping/.meta/design.md
index 787d008f21..c25ac8326e 100644
--- a/exercises/concept/object-relational-mapping/.meta/design.md
+++ b/exercises/concept/object-relational-mapping/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to clean up resources using `IDisposable` in C# for managed resources.
diff --git a/exercises/concept/orm-in-one-go/.docs/hints.md b/exercises/concept/orm-in-one-go/.docs/hints.md
index 77d1206bd1..285c6f93be 100644
--- a/exercises/concept/orm-in-one-go/.docs/hints.md
+++ b/exercises/concept/orm-in-one-go/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [using statement][using-statement] documentation describes how and when to use the `using` keyword.
diff --git a/exercises/concept/orm-in-one-go/.docs/instructions.md b/exercises/concept/orm-in-one-go/.docs/instructions.md
index 6f4e809c5b..106e38e0be 100644
--- a/exercises/concept/orm-in-one-go/.docs/instructions.md
+++ b/exercises/concept/orm-in-one-go/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You are back working on the ORM (Object Relationship Mapping) system introduced in (TODO cross-reference-tba).
 
 Our ORM usage analysis shows that 95% of transactions are executed from within one calling method, and it has been decided that it would be more appropriate to have a single ORM method that opened, wrote and committed a transaction.
diff --git a/exercises/concept/orm-in-one-go/.docs/introduction.md b/exercises/concept/orm-in-one-go/.docs/introduction.md
index ee0bef510d..6b15e3632f 100644
--- a/exercises/concept/orm-in-one-go/.docs/introduction.md
+++ b/exercises/concept/orm-in-one-go/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 You saw in (TODO cross-ref-tba) that the `IDispose` interface could be used to signal that some object's resource or other program state needed to be released or reset when the object was no longer required (and that relying on the garbage collector would not achieve this or provide the required level of control) and that `IDisposable.Dispose()` method was the natural place for such cleanup operations.
 
 There is another construct, the `using` block, that enables, from the caller's perspective, all the resource lifetime management to be gathered into a single statement.
diff --git a/exercises/concept/orm-in-one-go/.meta/design.md b/exercises/concept/orm-in-one-go/.meta/design.md
index 91bec19fbb..92ad4ae0d8 100644
--- a/exercises/concept/orm-in-one-go/.meta/design.md
+++ b/exercises/concept/orm-in-one-go/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to control a resource's lifetime with the `using` statement in C#.
diff --git a/exercises/concept/parsing-log-files/.docs/hints.md b/exercises/concept/parsing-log-files/.docs/hints.md
index 8774ee169d..9dcbb09d24 100644
--- a/exercises/concept/parsing-log-files/.docs/hints.md
+++ b/exercises/concept/parsing-log-files/.docs/hints.md
@@ -1,4 +1,4 @@
-## General
+# General
 
 - [regular expressions][regular-expressions] documentation describes regexes and the flavour built into the .NET libraries.
 - [Regex][regex] documentation describing the built-in library class.
diff --git a/exercises/concept/parsing-log-files/.docs/instructions.md b/exercises/concept/parsing-log-files/.docs/instructions.md
index 83d9285907..ec8c196692 100644
--- a/exercises/concept/parsing-log-files/.docs/instructions.md
+++ b/exercises/concept/parsing-log-files/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 This exercise addresses the parsing of log files.
 
 After a recent security review you have been asked to clean up the organization's archived log files.
diff --git a/exercises/concept/parsing-log-files/.docs/introduction.md b/exercises/concept/parsing-log-files/.docs/introduction.md
index 1256179199..d00e71bc27 100644
--- a/exercises/concept/parsing-log-files/.docs/introduction.md
+++ b/exercises/concept/parsing-log-files/.docs/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 The .NET base class libraries provide the `Regex` class for processing of regular expressions.
diff --git a/exercises/concept/parsing-log-files/.meta/design.md b/exercises/concept/parsing-log-files/.meta/design.md
index 1cb02f3472..43f3f044c6 100644
--- a/exercises/concept/parsing-log-files/.meta/design.md
+++ b/exercises/concept/parsing-log-files/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to use regular expressions with `Regex` in C#.
diff --git a/exercises/concept/phone-number-analysis/.docs/hints.md b/exercises/concept/phone-number-analysis/.docs/hints.md
index 0ce71dc00f..2bb9cfa8f2 100644
--- a/exercises/concept/phone-number-analysis/.docs/hints.md
+++ b/exercises/concept/phone-number-analysis/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ### General
 
 - [Tuples][tuples]: shows how to define and use tuples.
diff --git a/exercises/concept/phone-number-analysis/.docs/instructions.md b/exercises/concept/phone-number-analysis/.docs/instructions.md
index c08173254c..7c08a8eca3 100644
--- a/exercises/concept/phone-number-analysis/.docs/instructions.md
+++ b/exercises/concept/phone-number-analysis/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 This exercise has you analyze phone numbers.
 
 You are asked to implement 2 features.
diff --git a/exercises/concept/phone-number-analysis/.docs/introduction.md b/exercises/concept/phone-number-analysis/.docs/introduction.md
index 88510ef0c5..fdef63ec8a 100644
--- a/exercises/concept/phone-number-analysis/.docs/introduction.md
+++ b/exercises/concept/phone-number-analysis/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, a tuple is a data structure which organizes data, holding two or more fields
 of any type.
 
diff --git a/exercises/concept/phone-number-analysis/.meta/design.md b/exercises/concept/phone-number-analysis/.meta/design.md
index c7ffdecce8..2271ccb60c 100644
--- a/exercises/concept/phone-number-analysis/.meta/design.md
+++ b/exercises/concept/phone-number-analysis/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what a tuple is.
diff --git a/exercises/concept/red-vs-blue-darwin-style/.docs/hints.md b/exercises/concept/red-vs-blue-darwin-style/.docs/hints.md
index f22dc3dbe2..fde679ed22 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.docs/hints.md
+++ b/exercises/concept/red-vs-blue-darwin-style/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Namespaces][namespaces]: how to define and import namespaces.
diff --git a/exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md b/exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md
index 20754b7313..3406f54e94 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md
+++ b/exercises/concept/red-vs-blue-darwin-style/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Management are starting to apply Darwinian principles to the Remote Control Car project (TODO cross-ref-tba). The developers have been split into two teams, _Red_ and _Blue_, and are tasked with improving the design independently of each other. They don't need to concern themselves with design decisions of the other team.
 
 You have been asked to take a look at the code and see how you can best combine the two efforts for testing purposes.
diff --git a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
index ccfd49113a..0e2879c6a8 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
+++ b/exercises/concept/red-vs-blue-darwin-style/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Namespaces are a way to group related code and to avoid name clashes and are generally present in all but the most trivial code base.
 
 The syntax is as follows:
diff --git a/exercises/concept/red-vs-blue-darwin-style/.meta/design.md b/exercises/concept/red-vs-blue-darwin-style/.meta/design.md
index 88c24ce4df..ef38687a16 100644
--- a/exercises/concept/red-vs-blue-darwin-style/.meta/design.md
+++ b/exercises/concept/red-vs-blue-darwin-style/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what namespaces are.
diff --git a/exercises/concept/remote-control-cleanup/.docs/hints.md b/exercises/concept/remote-control-cleanup/.docs/hints.md
index 2180486ec5..481b052177 100644
--- a/exercises/concept/remote-control-cleanup/.docs/hints.md
+++ b/exercises/concept/remote-control-cleanup/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - This documentation of [nested types][nested-types] details the syntax.
diff --git a/exercises/concept/remote-control-cleanup/.docs/instructions.md b/exercises/concept/remote-control-cleanup/.docs/instructions.md
index 01fa43484a..8bab82469d 100644
--- a/exercises/concept/remote-control-cleanup/.docs/instructions.md
+++ b/exercises/concept/remote-control-cleanup/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Some "other" developers have been working on the remote control car project (TODO cross-ref-tba). You have been called in to clean up the code.
 
 ## 1. Separate concerns between the car itself and the telemetry system
diff --git a/exercises/concept/remote-control-cleanup/.docs/introduction.md b/exercises/concept/remote-control-cleanup/.docs/introduction.md
index 1edafdd14b..8c815d506b 100644
--- a/exercises/concept/remote-control-cleanup/.docs/introduction.md
+++ b/exercises/concept/remote-control-cleanup/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 C# types can be defined within the scope of a class or struct. The enclosing type provides a kind of name space. Access to the type is through the enclosing type with dot syntax.
 
 ```csharp
diff --git a/exercises/concept/remote-control-cleanup/.meta/design.md b/exercises/concept/remote-control-cleanup/.meta/design.md
index 53a2e4e40a..68eb0e4dd0 100644
--- a/exercises/concept/remote-control-cleanup/.meta/design.md
+++ b/exercises/concept/remote-control-cleanup/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how and why to use nested classes in C#.
diff --git a/exercises/concept/remote-control-competition/.docs/hints.md b/exercises/concept/remote-control-competition/.docs/hints.md
index 0c2096f63e..f146184b3d 100644
--- a/exercises/concept/remote-control-competition/.docs/hints.md
+++ b/exercises/concept/remote-control-competition/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Interface][interface]: what an interface is and how to implement it.
diff --git a/exercises/concept/remote-control-competition/.docs/instructions.md b/exercises/concept/remote-control-competition/.docs/instructions.md
index d765431561..b0c54d66a1 100644
--- a/exercises/concept/remote-control-competition/.docs/instructions.md
+++ b/exercises/concept/remote-control-competition/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you will be doing some more work on remote control cars.
 
 An experimental car has been developed and the test track needs to be adapted to handle both production and experimental models. The two types of car have already been built and you need to find a way to deal with them both on the test track.
diff --git a/exercises/concept/remote-control-competition/.docs/introduction.md b/exercises/concept/remote-control-competition/.docs/introduction.md
index 47bb2656c6..bc41aae256 100644
--- a/exercises/concept/remote-control-competition/.docs/introduction.md
+++ b/exercises/concept/remote-control-competition/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Interfaces
 
 An interface is a type containing members defining a group of related functionality. It distances the uses of a class from the implementation allowing multiple different implementations or support for some generic behavior such as formatting, comparison or conversion.
diff --git a/exercises/concept/remote-control-competition/.meta/design.md b/exercises/concept/remote-control-competition/.meta/design.md
index b04f01ccb6..aa7ba9f4d5 100644
--- a/exercises/concept/remote-control-competition/.meta/design.md
+++ b/exercises/concept/remote-control-competition/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what interfaces are.
diff --git a/exercises/concept/roll-the-die/.docs/hints.md b/exercises/concept/roll-the-die/.docs/hints.md
index cf5a6f97f3..9d90d878ef 100644
--- a/exercises/concept/roll-the-die/.docs/hints.md
+++ b/exercises/concept/roll-the-die/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ### General
 
 This [article][system-random] is an excellent introduction to the subject.
diff --git a/exercises/concept/roll-the-die/.docs/instructions.md b/exercises/concept/roll-the-die/.docs/instructions.md
index c0282a1897..c64bd6acd1 100644
--- a/exercises/concept/roll-the-die/.docs/instructions.md
+++ b/exercises/concept/roll-the-die/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Continuing the theme of the wizards and warriors game, it is time to add an all purpose die rolling method. This will be the traditional 18 sided die with numbers 1 to 18. Players also generate a spell strength.
 
 ## 1. Enable a _wizards and warriors_ player to roll a die.
diff --git a/exercises/concept/roll-the-die/.docs/introduction.md b/exercises/concept/roll-the-die/.docs/introduction.md
index 264aec91ec..f49401bb66 100644
--- a/exercises/concept/roll-the-die/.docs/introduction.md
+++ b/exercises/concept/roll-the-die/.docs/introduction.md
@@ -1 +1,3 @@
+# Introduction
+
 In C# randomness is achieved with the help of `System.Random`. Typically, you create an instance and then call one of its `Next()` or `NextDouble()` methods, possibly multiple times depending on the use-case.
diff --git a/exercises/concept/roll-the-die/.meta/design.md b/exercises/concept/roll-the-die/.meta/design.md
index 96cd8310d9..e37e14192f 100644
--- a/exercises/concept/roll-the-die/.meta/design.md
+++ b/exercises/concept/roll-the-die/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know how to implement randomness with `System.Random` in C#.
diff --git a/exercises/concept/secure-munchester-united/.docs/hints.md b/exercises/concept/secure-munchester-united/.docs/hints.md
index 339d69c453..ca97ec2c6d 100644
--- a/exercises/concept/secure-munchester-united/.docs/hints.md
+++ b/exercises/concept/secure-munchester-united/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Type testing and cast operators][type-testing-and-cast-operators]: introduction to type testing and casting.
diff --git a/exercises/concept/secure-munchester-united/.docs/instructions.md b/exercises/concept/secure-munchester-united/.docs/instructions.md
index 350888d6a9..83683fe223 100644
--- a/exercises/concept/secure-munchester-united/.docs/instructions.md
+++ b/exercises/concept/secure-munchester-united/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 Our football club (first encountered in (TODO cross-ref-tba)) is soaring in the leagues, and you have been invited to do some more work, this time on the security pass printing system.
 
 The class hierarchy of the backroom staff is as follows
diff --git a/exercises/concept/secure-munchester-united/.docs/introduction.md b/exercises/concept/secure-munchester-united/.docs/introduction.md
index d05ff9408e..f2643ac03c 100644
--- a/exercises/concept/secure-munchester-united/.docs/introduction.md
+++ b/exercises/concept/secure-munchester-united/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 Casting and type conversion are different ways of changing an expression from one data type to another.
 
 An expression can be cast to another type with the cast operator `()`.
diff --git a/exercises/concept/secure-munchester-united/.meta/design.md b/exercises/concept/secure-munchester-united/.meta/design.md
index 0f9d6d0e75..82a5c85879 100644
--- a/exercises/concept/secure-munchester-united/.meta/design.md
+++ b/exercises/concept/secure-munchester-united/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what explicit and implicit casts are.
diff --git a/exercises/concept/squeaky-clean/.docs/hints.md b/exercises/concept/squeaky-clean/.docs/hints.md
index 2610b7b655..5113a8ef9f 100644
--- a/exercises/concept/squeaky-clean/.docs/hints.md
+++ b/exercises/concept/squeaky-clean/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ### 1. Replace any spaces encountered with underscores
 
 - [This tutorial][chars-tutorial] is useful.
diff --git a/exercises/concept/squeaky-clean/.docs/instructions.md b/exercises/concept/squeaky-clean/.docs/instructions.md
index 1e2ac42934..1edfe325ae 100644
--- a/exercises/concept/squeaky-clean/.docs/instructions.md
+++ b/exercises/concept/squeaky-clean/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you will implement a partial set of utility routines to help a developer
 clean up identifier names.
 
diff --git a/exercises/concept/squeaky-clean/.docs/introduction.md b/exercises/concept/squeaky-clean/.docs/introduction.md
index 92830e8874..e380223238 100644
--- a/exercises/concept/squeaky-clean/.docs/introduction.md
+++ b/exercises/concept/squeaky-clean/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Chars
 
 The C# `char` type is a 16 bit quantity to represent the smallest addressable components of text.
diff --git a/exercises/concept/squeaky-clean/.meta/design.md b/exercises/concept/squeaky-clean/.meta/design.md
index 1128c7d39f..5ecd556dd6 100644
--- a/exercises/concept/squeaky-clean/.meta/design.md
+++ b/exercises/concept/squeaky-clean/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `char` type.
diff --git a/exercises/concept/the-weather-in-deather/.docs/hints.md b/exercises/concept/the-weather-in-deather/.docs/hints.md
index aff0a17b44..e3126ae4ca 100644
--- a/exercises/concept/the-weather-in-deather/.docs/hints.md
+++ b/exercises/concept/the-weather-in-deather/.docs/hints.md
@@ -1,4 +1,4 @@
-## General
+# General
 
 - Expression bodied members are discussed [here][expression-bodied-members].
 - Ternary operators are discussed [here][ternary-operators].
diff --git a/exercises/concept/the-weather-in-deather/.docs/instructions.md b/exercises/concept/the-weather-in-deather/.docs/instructions.md
index 41b75cee07..60ea56218b 100644
--- a/exercises/concept/the-weather-in-deather/.docs/instructions.md
+++ b/exercises/concept/the-weather-in-deather/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 You have been asked to improve some legacy code relating to a weather station.
 
 The weather station accepts readings, and outputs some indicators such as temperature and pressure.
diff --git a/exercises/concept/the-weather-in-deather/.docs/introduction.md b/exercises/concept/the-weather-in-deather/.docs/introduction.md
index c79b3ffd0d..41f2344a56 100644
--- a/exercises/concept/the-weather-in-deather/.docs/introduction.md
+++ b/exercises/concept/the-weather-in-deather/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Expression Bodied Members
 
 Many types of struct and class members (fields being the primary exception) can use the expression-bodied member syntax. Defining a member with an expression often produces more concise and readable code than traditional blocks/statements.
diff --git a/exercises/concept/the-weather-in-deather/.meta/design.md b/exercises/concept/the-weather-in-deather/.meta/design.md
index e5d5f559d1..20cb54b17a 100644
--- a/exercises/concept/the-weather-in-deather/.meta/design.md
+++ b/exercises/concept/the-weather-in-deather/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know the difference between statements and expressions.
diff --git a/exercises/concept/tim-from-marketing/.docs/hints.md b/exercises/concept/tim-from-marketing/.docs/hints.md
index dc29d8bdc6..77d1cbe86f 100644
--- a/exercises/concept/tim-from-marketing/.docs/hints.md
+++ b/exercises/concept/tim-from-marketing/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## 1. Print a badge for an employee
 
 - [String interpolation][string-interpolation] can be used to concisely format the badge.
diff --git a/exercises/concept/tim-from-marketing/.docs/instructions.md b/exercises/concept/tim-from-marketing/.docs/instructions.md
index 3c383a9e2c..f611adc4bc 100644
--- a/exercises/concept/tim-from-marketing/.docs/instructions.md
+++ b/exercises/concept/tim-from-marketing/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be writing code to print name badges for factory employees.
 
 ## 1. Print a badge for an employee
diff --git a/exercises/concept/tim-from-marketing/.docs/introduction.md b/exercises/concept/tim-from-marketing/.docs/introduction.md
index 6ce9868e2e..79dacc2a7c 100644
--- a/exercises/concept/tim-from-marketing/.docs/introduction.md
+++ b/exercises/concept/tim-from-marketing/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, the `null` literal is used to denote the absence of a value. A _nullable_ type is a type that allows for `null` values.
 
 Prior to C# 8.0, reference types were always nullable and value types were not. A value type can be made nullable though by appending it with a question mark (`?`).
diff --git a/exercises/concept/tim-from-marketing/.meta/design.md b/exercises/concept/tim-from-marketing/.meta/design.md
index 7490c2a55f..d0a67d55ca 100644
--- a/exercises/concept/tim-from-marketing/.meta/design.md
+++ b/exercises/concept/tim-from-marketing/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know of the existence of the `null` literal.
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md
index 242830716e..c3937690d5 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [List documentation][lists-docs]: reference documentation for `List`.
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md
index 769a6f4f14..0cc8cc42ec 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be writing code to keep track of a list of programming languages you want to learn on Exercism.
 
 You have nine tasks, which will all involve dealing with lists.
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
index 18d037e5e1..ee13227bad 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Lists
 
 Lists in C# are collections of primitive values or instances of structs or classes. They are implemented in the base class library as `List` where `T` is the type of the item in the list. The API exposes a rich set of methods for creating and manipulating lists.
diff --git a/exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md b/exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md
index 7e64c50d6f..939c3ccf55 100644
--- a/exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md
+++ b/exercises/concept/tracks-on-tracks-on-tracks/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what generic types are.
diff --git a/exercises/concept/weighing-machine/.docs/hints.md b/exercises/concept/weighing-machine/.docs/hints.md
index 021e74b7f4..339a876bb2 100644
--- a/exercises/concept/weighing-machine/.docs/hints.md
+++ b/exercises/concept/weighing-machine/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Properties][docs.microsoft.com-properties]
diff --git a/exercises/concept/weighing-machine/.docs/instructions.md b/exercises/concept/weighing-machine/.docs/instructions.md
index 2379deee47..97ccfefb15 100644
--- a/exercises/concept/weighing-machine/.docs/instructions.md
+++ b/exercises/concept/weighing-machine/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you'll be modelling a weighing machine.
 
 The weight can be set and retrieved in pounds or kilograms and cannot be negative.
diff --git a/exercises/concept/weighing-machine/.docs/introduction.md b/exercises/concept/weighing-machine/.docs/introduction.md
index 1405dddcca..c5706faf8c 100644
--- a/exercises/concept/weighing-machine/.docs/introduction.md
+++ b/exercises/concept/weighing-machine/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 A property in C# is a member of a class that provides access to data within that class.
 Callers can set or retrieve (get) the data. Properties can be either auto-implemented or
 have a backing field. They comprise a set accessor and/or a get accessor.
diff --git a/exercises/concept/weighing-machine/.meta/design.md b/exercises/concept/weighing-machine/.meta/design.md
index 648f8a0120..8571f913a0 100644
--- a/exercises/concept/weighing-machine/.meta/design.md
+++ b/exercises/concept/weighing-machine/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 Properties are covered early in the C# track as their purpose and power can be shown with few dependencies (classes, access modifiers and fields of simple types).
 
 ## Learning objectives
diff --git a/exercises/concept/wizards-and-warriors-2/.docs/hints.md b/exercises/concept/wizards-and-warriors-2/.docs/hints.md
index 81e1b8e59f..575c6e7576 100644
--- a/exercises/concept/wizards-and-warriors-2/.docs/hints.md
+++ b/exercises/concept/wizards-and-warriors-2/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## General
 
 - [Method overloading in C#][member-overloading].
diff --git a/exercises/concept/wizards-and-warriors-2/.docs/instructions.md b/exercises/concept/wizards-and-warriors-2/.docs/instructions.md
index d69f819c1d..504ea9a544 100644
--- a/exercises/concept/wizards-and-warriors-2/.docs/instructions.md
+++ b/exercises/concept/wizards-and-warriors-2/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you're playing a role-playing game named "Wizard and Warriors" with your best friends. You are the Game Master, the person tasked with making the game world come alive for the players. A key aspect of this is describing the game to the players: what is a character's status, what the town they're visiting looks like, etc.
 
 You have five tasks that have you describe parts of the game to the players.
diff --git a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
index 0fffa16375..c92e4fddc8 100644
--- a/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
+++ b/exercises/concept/wizards-and-warriors-2/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 ## Method Overloading
 
 _Method overloading_ allows multiple methods in the same class to have the same name. Overloaded methods must be different from each other by either:
diff --git a/exercises/concept/wizards-and-warriors-2/.meta/design.md b/exercises/concept/wizards-and-warriors-2/.meta/design.md
index 233480bcb3..fdcf0a7e67 100644
--- a/exercises/concept/wizards-and-warriors-2/.meta/design.md
+++ b/exercises/concept/wizards-and-warriors-2/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what method overloading is
diff --git a/exercises/concept/wizards-and-warriors/.docs/hints.md b/exercises/concept/wizards-and-warriors/.docs/hints.md
index 01dda0bea1..2f536d9003 100644
--- a/exercises/concept/wizards-and-warriors/.docs/hints.md
+++ b/exercises/concept/wizards-and-warriors/.docs/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 ## 1. Describe a character
 
 - Modify the [constructors][constructor-syntax] of the `Wizard` and `Warrior` classes to pass their character type to the [base class' constructor][instance-constructors].
diff --git a/exercises/concept/wizards-and-warriors/.docs/instructions.md b/exercises/concept/wizards-and-warriors/.docs/instructions.md
index cf4321f055..09426bb9ac 100644
--- a/exercises/concept/wizards-and-warriors/.docs/instructions.md
+++ b/exercises/concept/wizards-and-warriors/.docs/instructions.md
@@ -1,3 +1,5 @@
+# Instructions
+
 In this exercise you're playing a role-playing game named "Wizard and Warriors," which allows you to play as either a Wizard or a Warrior.
 
 There are different rules for Warriors and Wizards to determine how much damage points they deal.
diff --git a/exercises/concept/wizards-and-warriors/.docs/introduction.md b/exercises/concept/wizards-and-warriors/.docs/introduction.md
index 32a4f8d3b0..231a4f9b25 100644
--- a/exercises/concept/wizards-and-warriors/.docs/introduction.md
+++ b/exercises/concept/wizards-and-warriors/.docs/introduction.md
@@ -1,3 +1,5 @@
+# Introduction
+
 In C#, a _class_ hierarchy can be defined using _inheritance_, which allows a derived class (`Car`) to inherit the behavior and data of its parent class (`Vehicle`). If no parent is specified, the class inherits from the `object` class.
 
 Parent classes can provide functionality to derived classes in three ways:
diff --git a/exercises/concept/wizards-and-warriors/.meta/design.md b/exercises/concept/wizards-and-warriors/.meta/design.md
index 02935724e6..2dc6c9b90c 100644
--- a/exercises/concept/wizards-and-warriors/.meta/design.md
+++ b/exercises/concept/wizards-and-warriors/.meta/design.md
@@ -1,3 +1,5 @@
+# Design
+
 ## Learning objectives
 
 - Know what inheritance is.
diff --git a/exercises/practice/accumulate/.meta/hints.md b/exercises/practice/accumulate/.meta/hints.md
index 202396f76d..1d904012b4 100644
--- a/exercises/practice/accumulate/.meta/hints.md
+++ b/exercises/practice/accumulate/.meta/hints.md
@@ -1,3 +1,5 @@
+# Hints
+
 To be more specific, you are not allowed to use any of the built-in [LINQ methods](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=netcore-2.1#methods).
 
 ### Laziness test
diff --git a/exercises/practice/allergies/.meta/hints.md b/exercises/practice/allergies/.meta/hints.md
index 9f27937eec..15bd61e2e4 100644
--- a/exercises/practice/allergies/.meta/hints.md
+++ b/exercises/practice/allergies/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 This exercise requires you to use bitwise operations. For more information, see [this page](https://msdn.microsoft.com/en-us/library/6a71f45d.aspx). 
\ No newline at end of file
diff --git a/exercises/practice/alphametics/.meta/hints.md b/exercises/practice/alphametics/.meta/hints.md
index ad5e51451c..72f3079a6f 100644
--- a/exercises/practice/alphametics/.meta/hints.md
+++ b/exercises/practice/alphametics/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 - To parse the text, you could try to use the [Sprache](https://github.com/sprache/Sprache/blob/develop/README.md) library. You can also find a good tutorial [here](https://www.thomaslevesque.com/2017/02/23/easy-text-parsing-in-c-with-sprache/).
 - You can solve this exercise with a brute force algorithm, but this will possibly have a poor runtime performance.
 Try to find a more sophisticated solution. 
diff --git a/exercises/practice/bank-account/.meta/hints.md b/exercises/practice/bank-account/.meta/hints.md
index 11fb837071..abe7c8b677 100644
--- a/exercises/practice/bank-account/.meta/hints.md
+++ b/exercises/practice/bank-account/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to handle data related to currency and money. A normal approuch is to use the [Decimal](https://msdn.microsoft.com/en-US/library/system.decimal.aspx) struct to store currency values. 
 Note though that you then only store the numeric value of a currency. 
diff --git a/exercises/practice/beer-song/.meta/hints.md b/exercises/practice/beer-song/.meta/hints.md
index ec02ddbc5d..9ead4d3d63 100644
--- a/exercises/practice/beer-song/.meta/hints.md
+++ b/exercises/practice/beer-song/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - Try to capture the structure of the song in your code, where you build up the song by composing its parts.
\ No newline at end of file
diff --git a/exercises/practice/clock/.meta/hints.md b/exercises/practice/clock/.meta/hints.md
index 9029f70d00..57baac2564 100644
--- a/exercises/practice/clock/.meta/hints.md
+++ b/exercises/practice/clock/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to implement a type-specific method for determining equality of instances.
 For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/api/System.IEquatable-1?view=netcore-2.1).
diff --git a/exercises/practice/custom-set/.meta/hints.md b/exercises/practice/custom-set/.meta/hints.md
index 729353db55..63e949aa87 100644
--- a/exercises/practice/custom-set/.meta/hints.md
+++ b/exercises/practice/custom-set/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 
 This exercise requires you to create custom equality comparison logic.
 For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netcore-2.0#System_Object_Equals_System_Object_).
diff --git a/exercises/practice/diamond/.meta/hints.md b/exercises/practice/diamond/.meta/hints.md
index 6904134da4..ffb4416c3e 100644
--- a/exercises/practice/diamond/.meta/hints.md
+++ b/exercises/practice/diamond/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 The tests in this exercise are different from your usual tests. Normally, a test checks if for a given input, the output matches the expected value. This is called *value-based testing*. However, this exercise uses *property-based testing*, where the tests check if for a range of inputs, the output has a specific property. The two key differences that differentiate property-based testing from value-based testing are:
 
 1. A property-based test works not with a single input value, but with many.
diff --git a/exercises/practice/difference-of-squares/.meta/hints.md b/exercises/practice/difference-of-squares/.meta/hints.md
index a3406761a8..e1d5a55744 100644
--- a/exercises/practice/difference-of-squares/.meta/hints.md
+++ b/exercises/practice/difference-of-squares/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 This exercise requires you to process a collection of data. You can simplify your code by using LINQ (Language Integrated Query).
 For more information, see [this page]
 (https://docs.microsoft.com/en-us/dotnet/articles/standard/using-linq).
\ No newline at end of file
diff --git a/exercises/practice/diffie-hellman/.meta/hints.md b/exercises/practice/diffie-hellman/.meta/hints.md
index 891e604413..f0af08bc4b 100644
--- a/exercises/practice/diffie-hellman/.meta/hints.md
+++ b/exercises/practice/diffie-hellman/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to perform calculations on large numbers. To correctly represent large numbers, the
 [BigInteger](https://msdn.microsoft.com/en-us/library/system.numerics.biginteger(v=vs.110).aspx) struct is used.
diff --git a/exercises/practice/dot-dsl/.meta/hints.md b/exercises/practice/dot-dsl/.meta/hints.md
index 6616bcf42e..3e57e33a01 100644
--- a/exercises/practice/dot-dsl/.meta/hints.md
+++ b/exercises/practice/dot-dsl/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 This exercise requires you to implement classes with a custom equality check. For more information, see [this page](https://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx).
\ No newline at end of file
diff --git a/exercises/practice/food-chain/.meta/hints.md b/exercises/practice/food-chain/.meta/hints.md
index 5911e1b558..095c174373 100644
--- a/exercises/practice/food-chain/.meta/hints.md
+++ b/exercises/practice/food-chain/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - Try to capture the structure of the song in your code, where you build up the song by composing its parts.
diff --git a/exercises/practice/forth/.meta/hints.md b/exercises/practice/forth/.meta/hints.md
index 02681d97d0..6517f74c29 100644
--- a/exercises/practice/forth/.meta/hints.md
+++ b/exercises/practice/forth/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - To parse the text, you could try to use the [Sprache](https://github.com/sprache/Sprache/blob/develop/README.md) library. You can also find a good tutorial [here](https://www.thomaslevesque.com/2017/02/23/easy-text-parsing-in-c-with-sprache/).
diff --git a/exercises/practice/hangman/.meta/hints.md b/exercises/practice/hangman/.meta/hints.md
index 205fb8d4c8..cc5a45c126 100644
--- a/exercises/practice/hangman/.meta/hints.md
+++ b/exercises/practice/hangman/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 This exercise requires you to work with Reactive extension. For more information, see 
 [this page](http://reactivex.io/intro.html) .
 
diff --git a/exercises/practice/house/.meta/hints.md b/exercises/practice/house/.meta/hints.md
index 9441f12d5a..849e94818d 100644
--- a/exercises/practice/house/.meta/hints.md
+++ b/exercises/practice/house/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 
 Try to capture the structure of the song in your code, where you build up the song by composing its parts.
\ No newline at end of file
diff --git a/exercises/practice/leap/.meta/hints.md b/exercises/practice/leap/.meta/hints.md
index fc5d233d4c..0b1a2e8ad7 100644
--- a/exercises/practice/leap/.meta/hints.md
+++ b/exercises/practice/leap/.meta/hints.md
@@ -1,4 +1,4 @@
-## Notes
+# Notes
 
 The DateTime class in C# provides a built-in [IsLeapYear](https://msdn.microsoft.com/en-us/library/system.datetime.isleapyear(v=vs.110).aspx) method
 which you should pretend doesn't exist for the purposes of implementing this exercise.
\ No newline at end of file
diff --git a/exercises/practice/list-ops/.meta/hints.md b/exercises/practice/list-ops/.meta/hints.md
index a352594b38..6f954bcc18 100644
--- a/exercises/practice/list-ops/.meta/hints.md
+++ b/exercises/practice/list-ops/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 The `Foldl` and `Foldr` methods are "fold" functions, which is a concept well-known in the functional programming world, but less so in the object-oriented one. If you'd like more background information, check out this [fold](https://en.wikipedia.org/wiki/Fold_(higher-order_function)) page.
\ No newline at end of file
diff --git a/exercises/practice/markdown/.meta/hints.md b/exercises/practice/markdown/.meta/hints.md
index 768ce82a91..3828f0b8a8 100644
--- a/exercises/practice/markdown/.meta/hints.md
+++ b/exercises/practice/markdown/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 For this exercise the following C# feature comes in handy:
 - [String Interpolation](https://msdn.microsoft.com/en-us/library/dn961160.aspx) (C# 6 and up).
\ No newline at end of file
diff --git a/exercises/practice/nth-prime/.meta/hints.md b/exercises/practice/nth-prime/.meta/hints.md
index 59b9952d90..94f5adc17b 100644
--- a/exercises/practice/nth-prime/.meta/hints.md
+++ b/exercises/practice/nth-prime/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 
 For this exercise the following C# feature comes in handy: 
 Enumerables are evaluated lazily.    They allow you to work with an infinite sequence of values.
diff --git a/exercises/practice/nucleotide-count/.meta/hints.md b/exercises/practice/nucleotide-count/.meta/hints.md
index cc5d04f58e..9403c11d5f 100644
--- a/exercises/practice/nucleotide-count/.meta/hints.md
+++ b/exercises/practice/nucleotide-count/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires the use of a Dictionary. For more information see 
 [this page.](https://msdn.microsoft.com/en-us/library/s4ys34ea(v=vs.110).aspx)
\ No newline at end of file
diff --git a/exercises/practice/palindrome-products/.meta/hints.md b/exercises/practice/palindrome-products/.meta/hints.md
index 5f09454a1c..ad08e19726 100644
--- a/exercises/practice/palindrome-products/.meta/hints.md
+++ b/exercises/practice/palindrome-products/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 
 For this exercise, you will need to create a set of factors using tuples.
 For more information on tuples, see [this link](https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx).
\ No newline at end of file
diff --git a/exercises/practice/proverb/.meta/hints.md b/exercises/practice/proverb/.meta/hints.md
index b761677e56..a5385cedde 100644
--- a/exercises/practice/proverb/.meta/hints.md
+++ b/exercises/practice/proverb/.meta/hints.md
@@ -1,3 +1,3 @@
-## HINTS
+# HINTS
 
 Try to capture the structure of the song in your code, where you build up the song by composing its parts.
\ No newline at end of file
diff --git a/exercises/practice/rational-numbers/hints.md b/exercises/practice/rational-numbers/hints.md
index 18b873b5b2..d648a8c5f4 100644
--- a/exercises/practice/rational-numbers/hints.md
+++ b/exercises/practice/rational-numbers/hints.md
@@ -1,4 +1,4 @@
-## Hints		
+# Hints		
 This exercise requires you to write an extension method. For more information, see [this page](https://msdn.microsoft.com/en-us//library/bb383977.aspx).
 
 This exercise also requires you to write operator overloading methods for +, -, * and / operators. For more information, see [this page](https://msdn.microsoft.com/en-us/library/5tk49fh2.aspx).
diff --git a/exercises/practice/react/.meta/hints.md b/exercises/practice/react/.meta/hints.md
index 112fff4109..75de3a087d 100644
--- a/exercises/practice/react/.meta/hints.md
+++ b/exercises/practice/react/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 In this exercise the following C# feature is used:
 - [Events](https://msdn.microsoft.com/en-us/library/9aackb16(v=vs.110).aspx).
\ No newline at end of file
diff --git a/exercises/practice/roman-numerals/.meta/hints.md b/exercises/practice/roman-numerals/.meta/hints.md
index b36e1ce4ae..a74f883873 100644
--- a/exercises/practice/roman-numerals/.meta/hints.md
+++ b/exercises/practice/roman-numerals/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 This exercise requires you to write an extension method. For more information, see [this page](https://msdn.microsoft.com/en-us//library/bb383977.aspx).
diff --git a/exercises/practice/saddle-points/.meta/hints.md b/exercises/practice/saddle-points/.meta/hints.md
index 5f09454a1c..ad08e19726 100644
--- a/exercises/practice/saddle-points/.meta/hints.md
+++ b/exercises/practice/saddle-points/.meta/hints.md
@@ -1,4 +1,4 @@
-## Hints
+# Hints
 
 For this exercise, you will need to create a set of factors using tuples.
 For more information on tuples, see [this link](https://msdn.microsoft.com/en-us/library/system.tuple(v=vs.110).aspx).
\ No newline at end of file
diff --git a/exercises/practice/sgf-parsing/.meta/hints.md b/exercises/practice/sgf-parsing/.meta/hints.md
index 02681d97d0..6517f74c29 100644
--- a/exercises/practice/sgf-parsing/.meta/hints.md
+++ b/exercises/practice/sgf-parsing/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - To parse the text, you could try to use the [Sprache](https://github.com/sprache/Sprache/blob/develop/README.md) library. You can also find a good tutorial [here](https://www.thomaslevesque.com/2017/02/23/easy-text-parsing-in-c-with-sprache/).
diff --git a/exercises/practice/simple-linked-list/.meta/hints.md b/exercises/practice/simple-linked-list/.meta/hints.md
index 116e76c569..af13a9bba4 100644
--- a/exercises/practice/simple-linked-list/.meta/hints.md
+++ b/exercises/practice/simple-linked-list/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to create a linked list data structure which can be iterated. This requires you to implement the IEnumerable\ interface. 
 For more information, see [this page](https://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110).aspx).
\ No newline at end of file
diff --git a/exercises/practice/sublist/.meta/hints.md b/exercises/practice/sublist/.meta/hints.md
index 71240f0f72..d1cd842458 100644
--- a/exercises/practice/sublist/.meta/hints.md
+++ b/exercises/practice/sublist/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 To be able to compare data, the IComparable interface is used.
 For more information, see [this page](https://msdn.microsoft.com/en-us/library/system.icomparable(v=vs.110).aspx).
diff --git a/exercises/practice/sum-of-multiples/.meta/hints.md b/exercises/practice/sum-of-multiples/.meta/hints.md
index 16cad5e66b..ee3a040db3 100644
--- a/exercises/practice/sum-of-multiples/.meta/hints.md
+++ b/exercises/practice/sum-of-multiples/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to process a collection of data. You can simplify your code by using LINQ (Language Integrated Query).
 For more information, see [this page](https://docs.microsoft.com/en-us/dotnet/articles/standard/using-linq).
\ No newline at end of file
diff --git a/exercises/practice/twelve-days/.meta/hints.md b/exercises/practice/twelve-days/.meta/hints.md
index 5911e1b558..095c174373 100644
--- a/exercises/practice/twelve-days/.meta/hints.md
+++ b/exercises/practice/twelve-days/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - Try to capture the structure of the song in your code, where you build up the song by composing its parts.
diff --git a/exercises/practice/variable-length-quantity/.meta/hints.md b/exercises/practice/variable-length-quantity/.meta/hints.md
index fafdb6b18d..ff7733d6bd 100644
--- a/exercises/practice/variable-length-quantity/.meta/hints.md
+++ b/exercises/practice/variable-length-quantity/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to use bitwise operations. For more information, see [this page]
 (https://msdn.microsoft.com/en-us/library/6a71f45d.aspx). 
diff --git a/exercises/practice/word-search/.meta/hints.md b/exercises/practice/word-search/.meta/hints.md
index f072d5307c..d4d4292049 100644
--- a/exercises/practice/word-search/.meta/hints.md
+++ b/exercises/practice/word-search/.meta/hints.md
@@ -1,4 +1,4 @@
-## HINTS
+# HINTS
 
 One of the uses of Tuples is returning multiple values from a function.   In this exercise, write
 a function that returns a Tuple (the x- and y- part of a coordinate).
diff --git a/exercises/practice/wordy/.meta/hints.md b/exercises/practice/wordy/.meta/hints.md
index 02681d97d0..6517f74c29 100644
--- a/exercises/practice/wordy/.meta/hints.md
+++ b/exercises/practice/wordy/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 - To parse the text, you could try to use the [Sprache](https://github.com/sprache/Sprache/blob/develop/README.md) library. You can also find a good tutorial [here](https://www.thomaslevesque.com/2017/02/23/easy-text-parsing-in-c-with-sprache/).
diff --git a/exercises/practice/zebra-puzzle/.meta/hints.md b/exercises/practice/zebra-puzzle/.meta/hints.md
index 62dfafac83..fe1aa34a24 100644
--- a/exercises/practice/zebra-puzzle/.meta/hints.md
+++ b/exercises/practice/zebra-puzzle/.meta/hints.md
@@ -1,3 +1,3 @@
-## Hints
+# Hints
 This exercise requires you to process a collection of data. You can simplify your code by using lazy sequences to improve performance.
 For more information, see [this page](https://xosfaere.wordpress.com/2010/03/21/lazy-evaluation-in-csharp/).
diff --git a/exercises/practice/zipper/.meta/hints.md b/exercises/practice/zipper/.meta/hints.md
index 3bafe687b4..56370a753c 100644
--- a/exercises/practice/zipper/.meta/hints.md
+++ b/exercises/practice/zipper/.meta/hints.md
@@ -1,2 +1,2 @@
-## Hints
+# Hints
 This exercise deals with custom equality. For more information see [this page.](http://www.loganfranken.com/blog/687/overriding-equals-in-c-part-1/)
diff --git a/reference/exercise-concepts/isbn-verifier.md b/reference/exercise-concepts/isbn-verifier.md
index feda0133dc..799c563f3f 100644
--- a/reference/exercise-concepts/isbn-verifier.md
+++ b/reference/exercise-concepts/isbn-verifier.md
@@ -1,3 +1,5 @@
+# isbn verifier
+
 [Example implementation](https://github.com/exercism/csharp/blob/master/exercises/isbn-verifier/Example.cs)
 
 ## General

From 95adede4608f8f59cd8ecca3a0c734be85285b80 Mon Sep 17 00:00:00 2001
From: Erik Schierboom 
Date: Tue, 9 Feb 2021 12:23:21 +0100
Subject: [PATCH 327/327] [v3] Markdown sub-headings must be parent level
 incremented by one.

The full specification can be found [here](https://github.com/exercism/docs/blob/main/contributing/standards/markdown.md).
---
 concepts/casting/about.md                     | 12 +++++-----
 concepts/chars/about.md                       |  6 ++---
 concepts/constants/about.md                   |  4 ++--
 concepts/equality/about.md                    |  6 ++---
 concepts/equality/introduction.md             |  2 +-
 concepts/integral-numbers/about.md            |  6 ++---
 concepts/integral-numbers/introduction.md     |  2 +-
 concepts/interfaces/about.md                  |  4 ++--
 concepts/lists/about.md                       |  2 +-
 concepts/namespaces/about.md                  |  6 ++---
 concepts/nested-types/about.md                |  6 ++---
 concepts/operator-overloading/about.md        |  2 +-
 concepts/parameters/about.md                  |  2 +-
 concepts/properties/introduction.md           |  4 ++--
 concepts/randomness/about.md                  |  2 +-
 concepts/regular-expressions/about.md         |  4 ++--
 concepts/resource-cleanup/about.md            |  2 +-
 concepts/resource-lifetime/about.md           |  6 ++---
 concepts/string-formatting/about.md           | 14 ++++++------
 concepts/string-formatting/introduction.md    |  8 +++----
 concepts/structs/about.md                     |  6 ++---
 concepts/tuples/about.md                      | 10 ++++-----
 docs/INSTALLATION.md                          |  4 ++--
 docs/LEARNING.md                              |  6 ++---
 docs/RESOURCES.md                             | 10 ++++-----
 exercises/concept/faceid-2/.docs/hints.md     |  2 +-
 .../football-match-reports/.docs/hints.md     |  8 +++----
 .../.docs/instructions.md                     |  8 +++----
 .../.docs/introduction.md                     |  2 +-
 .../.docs/hints.md                            | 22 +++++++++----------
 .../.docs/instructions.md                     | 18 +++++++--------
 .../concept/parsing-log-files/.docs/hints.md  | 10 ++++-----
 .../parsing-log-files/.docs/instructions.md   | 10 ++++-----
 .../phone-number-analysis/.docs/hints.md      |  6 ++---
 .../.docs/instructions.md                     |  4 ++--
 exercises/concept/roll-the-die/.docs/hints.md |  6 ++---
 .../concept/squeaky-clean/.docs/hints.md      |  8 +++----
 .../squeaky-clean/.docs/instructions.md       |  8 +++----
 .../weighing-machine/.docs/introduction.md    |  4 ++--
 exercises/practice/accumulate/.meta/hints.md  |  2 +-
 exercises/practice/etl/README.md              |  6 ++---
 exercises/practice/grep/README.md             |  2 +-
 exercises/practice/rest-api/README.md         |  6 ++---
 exercises/practice/spiral-matrix/README.md    |  4 ++--
 exercises/practice/tournament/README.md       |  2 +-
 reference/implementing-a-concept-exercise.md  |  4 ++--
 reference/out-of-scope.md                     |  8 +++----
 47 files changed, 143 insertions(+), 143 deletions(-)

diff --git a/concepts/casting/about.md b/concepts/casting/about.md
index b29ee70c35..c4d3ef01f0 100644
--- a/concepts/casting/about.md
+++ b/concepts/casting/about.md
@@ -8,7 +8,7 @@ In C# very often, outside of the realm of numeric values and class hierarchies,
 
 Note that implicit an explicit cast [operators][operator-overloading] (discussed in (TODO cross-ref-tba)) are available which can bring fairly arbitrary casting to your own types.
 
-#### Casting Primitive Types - Implicit
+## Casting Primitive Types - Implicit
 
 C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value. Note in the documentation the exception for converting to real numbers where precision may be lost.
 
@@ -23,7 +23,7 @@ There is no implicit conversion of a numeric (or string) expression to `bool`. T
 
 An expression of type `char` can be implicitly cast to `int`. The cast in the opposite direction must be explicit. Not all values of `int` are valid utf 16 chars.
 
-#### Casting Primitive Types - Explicit
+## Casting Primitive Types - Explicit
 
 Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator].
 
@@ -31,7 +31,7 @@ Where the value being cast cannot be represented by the "to" type because it is
 
 An expression of type `int` can be explicitly cast to `char`. This may result in an invalid `char`.
 
-#### Casting Primitive Types - Examples
+## Casting Primitive Types - Examples
 
 ```csharp
 int largeInt = Int32.MaxValue;
@@ -61,7 +61,7 @@ int fromString_bad = Int32.Parse("forty two");     // FormatException is thrown
 
 See this [article][checked] for the _**checked**_ keyword.
 
-#### Type Conversion for types in a hierarchy
+## Type Conversion for types in a hierarchy
 
 Any type can be implicitly converted to its base class or interface.
 
@@ -112,13 +112,13 @@ if (r is Foo foo3)
 
 The [`as`][as-operator] keyword fulfills a similar function to `is` e.g. `var foo = ifoo as Foo;`. In this example `foo` will be `null` if `ifoo` is not of type `Foo` otherwise `ifoo` will be assigned to it.
 
-#### Custom Cast Operator
+## Custom Cast Operator
 
 Types can define their own custom explicit and implicit [cast operators][custom-casts]. See (TODO cross-ref-tba) for coverage of this..
 
 Examples of [explicit][big-integer-explicit] and [implicit][big-integer-implicit] casts in the BCL is conversions from the `BigInteger` struct to and from other numeric types
 
-#### Using `typeof`
+## Using `typeof`
 
 If you need to detect the precise type of an object then `is` may be a little too permissive as it will convert an object to a class or any of its base classes. `typeof` and `Object.GetType()` are the solution in this case.
 
diff --git a/concepts/chars/about.md b/concepts/chars/about.md
index 8430f64d9c..333f8b1c6e 100644
--- a/concepts/chars/about.md
+++ b/concepts/chars/about.md
@@ -14,7 +14,7 @@ These rough edges mostly relate to the opposition
 between the full unicode standard on the one side and historic representations
 of text as well as performance and memory usage on the other.
 
-### Unicode Issues
+## Unicode Issues
 
 When dealing with strings, if `System.String` library methods are available you should
 seek these out and use them rather than breaking the string down into characters.
@@ -45,7 +45,7 @@ is where you can use `String`'s library methods.
 If you do find yourself in the unenviable position of dealing with the minutiae of unicode
 then [this][char-encoding-net] is a good starting point.
 
-### Globalization
+## Globalization
 
 If you are working in an environment where you are dealing with multiple cultures or
 the culture is important in some parts of the code but not others then be
@@ -53,7 +53,7 @@ aware of the overloads of [`ToUpper`][to-upper] and [`ToLower`][to-lower] which
 [`ToUpperInvariant`][to-upper-invariant] and [`ToLowerInvariant`][to-lower-invariant] which will provide a consistent
 result irrespective of the current [culture][culture-info].
 
-### Representation, Characters and Integers
+## Representation, Characters and Integers
 
 Like other simple types (`int`s, `bool`s, etc.) the `char` has a companion
 or alias type, in this case, `System.Char`. This is in fact a `struct` with
diff --git a/concepts/constants/about.md b/concepts/constants/about.md
index 6acea2bb62..9445db3bc5 100644
--- a/concepts/constants/about.md
+++ b/concepts/constants/about.md
@@ -1,6 +1,6 @@
 # About
 
-#### const
+## const
 
 The [`const`][constants] modifier can be (and generally should be) applied to any field where its value is known at compile time and will not change during the lifetime of the program.
 
@@ -27,7 +27,7 @@ public double Area(double r)
 
 Identifying a value with `const` in this way can be useful if it is used multiple times in the method or you want to draw attention to its meaning. There is no performance gain over using literals inline.
 
-#### readonly
+## readonly
 
 The [`readonly`][readonly-fields] modifier can be (and generally should be) applied to any field that cannot be made `const` where its value will not change during the lifetime of the program and is either set by an inline initializer or during instantiation (by the constructor or a method called by the constructor).
 
diff --git a/concepts/equality/about.md b/concepts/equality/about.md
index a30fd17b02..95bc0a2f2f 100644
--- a/concepts/equality/about.md
+++ b/concepts/equality/about.md
@@ -2,9 +2,9 @@
 
 The coding exercise illustrates a number of properties of equality in C#:
 
-### `Object.Equals()`
+## `Object.Equals()`
 
-#### Topics covered by the coding exercise
+### Topics covered by the coding exercise
 
 - Simple types (strings and primitives) are typically tested for equality with the `==` and `!=`. This is considered more idiomatic than using the [`Equals()`][object-equals] method which is also available with these types. Java programmers should be alert, when dealing with strings, to the fact that `==` compares by value in C# but by reference in Java when returning to their former language.
 - Reference types (Instances of classes) are compared using the `Equals()` method inherited from `object`. If your goal with the equality test is to ensure that two objects are the exact same instance then relying on `object`'s implementation will suffice. If not, you need to override `object.Equals()`.
@@ -48,7 +48,7 @@ ReferenceEquals(winA, winC);
 // => true
 ```
 
-#### Ancillary topics
+### Ancillary topics
 
 - In addition to `public override bool Equals(object obj)` IDEs typically generate the overload `protected bool Equals(FacialFeatures other)` for use when inheritance is involved. A derived class can call the base classe's `Equals()` and then add its own test.
 - Do not use `==` unless you have [overloaded][operator-overloading] the `==` operator, as well as the `Equals()` method in your class (see the `operator-overloading` exercise) or you care only that the references are equal.
diff --git a/concepts/equality/introduction.md b/concepts/equality/introduction.md
index c27abfcc8c..0fe42cae53 100644
--- a/concepts/equality/introduction.md
+++ b/concepts/equality/introduction.md
@@ -10,7 +10,7 @@ An overridden `Equals()` method will contain equality tests on members of simple
 
 The `Object` class provides appropriate methods to compare two objects to detect if they are one and the same instance.
 
-### `Object.GetHashCode()`
+## `Object.GetHashCode()`
 
 The `Object.GetHashCode()` method returns a hash code in the form of a 32 bit integer. The hash code is used by _dictionary_ and _set_ classes such as `Dictionary` and `HashSet`to store and retrieve objects in a performant manner.
 
diff --git a/concepts/integral-numbers/about.md b/concepts/integral-numbers/about.md
index 86cad8b25b..9ca1ae3630 100644
--- a/concepts/integral-numbers/about.md
+++ b/concepts/integral-numbers/about.md
@@ -21,7 +21,7 @@ The types discussed so far are _primitive_ types. Each is paired with a `struct`
 | `uint`   | `UInt32` | 32 bit | 0                          | +4_294_967_295              |
 | `ulong`  | `UInt64` | 64 bit | 0                          | +18_446_744_073_709_551_615 |
 
-#### Casting
+## Casting
 
 A variable (or expression) of one type can easily be converted to another. For instance, in an assignment operation, if the type of the value being assigned (rhs) ensures that the value will fit within the range of the type being assigned to (lhs) then there is a simple assignment:
 
@@ -45,13 +45,13 @@ The requirement for casting is determined by the two types involved rather than
 
 The following paragraphs discuss the casting of integral types. (TODO cross-ref-tba casting) provides a broader discussion of casting and type conversion. See that documentation for a discussion of conversion between integral types and floating-point numbers, `char` and `bool`.
 
-##### Casting Primitive Types - Implicit
+### Casting Primitive Types - Implicit
 
 C#'s type system is somewhat stricter than _C_'s or Javascript's and as a consequence, casting operations are more restricted. [Implicit casting][implicit-casts] takes place between two numeric types as long as the "to" type can preserve the scale and sign of the "from" type's value.
 
 An implicit cast is not signified by any special syntax.
 
-##### Casting Primitive Types - Explicit
+### Casting Primitive Types - Explicit
 
 Where numeric types cannot be cast implicitly you can generally use the explicit cast [operator][cast-operator].
 
diff --git a/concepts/integral-numbers/introduction.md b/concepts/integral-numbers/introduction.md
index 714616a7a8..b85636f08f 100644
--- a/concepts/integral-numbers/introduction.md
+++ b/concepts/integral-numbers/introduction.md
@@ -31,6 +31,6 @@ short s = 42;
 uint ui = (uint)s;
 ```
 
-#### Bit conversion
+## Bit conversion
 
 The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes.
diff --git a/concepts/interfaces/about.md b/concepts/interfaces/about.md
index bfaa79cb58..6775a261ff 100644
--- a/concepts/interfaces/about.md
+++ b/concepts/interfaces/about.md
@@ -117,7 +117,7 @@ By design, C# does not support multiple inheritance, but it facilitates a kind o
 
 Moreover, the concept of [polymorphism can be implemented through interfaces][interface-polymorphism] underpins the interface mechanism.
 
-#### Explicit interface implementation
+## Explicit interface implementation
 
 Sometimes method names and signatures can be shared in two different interfaces.
 In order provide a distinct implementation of these methods, C# provides [explicit implementation of interfaces][explicit-implementation]. Note that to use a particular implementation of an interface you need to convert the expression containing referencing the object to that interface. Assignment, casting or passing as a parameter will achieve this.
@@ -166,7 +166,7 @@ There are a number of use cases:
 - Methods with the same name but different return types: if you implement your own collection classes you may find that an explicit interface for the legacy `IEnumerable.GetEnumerator()`, alongside `IEnumerable.GetEnuerator()`, is required. You may never make use of such the interface but the compiler may insist.
 - Methods where there is no clash of names between interfaces but it is desirable that the implementing class uses the name for some related purpose: `IFormattable` has a `ToString()` method which takes a _format type_ parameter as well as parameter of type `IFormatProvider`. A class like `FormattableString` from the Base Class Library (BCL) has the interface to ensure it can be used by routines that take an `IFormattable` but it is more expressive for its main version of `ToString(IFormatProvider)` to omit the _format type_ parameter as it is not used in the implementation and would confuse API users.
 
-#### Default implementation
+## Default implementation
 
 Version 8 of C# addresses a nagging problem with APIs. If you add methods to an interface to enhance functionality for new implementations then it is necessary to modify all the existing implementations of the interface so that they comply with the API-contract even though they have no implementation specific behavior. C# now allows for a _default method_ to be provided as part of the interface (Java developers will be familiar). Previously, when such a change occurred a _version 2_ of the interface would exist alongside the original.
 
diff --git a/concepts/lists/about.md b/concepts/lists/about.md
index eeaa64b525..5626942e82 100644
--- a/concepts/lists/about.md
+++ b/concepts/lists/about.md
@@ -13,7 +13,7 @@ A collection definition typically includes a place holder in angle brackets, oft
 
 Unlike arrays (TODO cross-ref-tba) lists can resize themselves dynamically.
 
-#### LINQ
+## LINQ
 
 Although the built-in API of `List` is rich (including mappings and filters such as `ConvertAll`, `FindAll` and `Foreach`) and its [looping syntax][for-each] is very clear, and you definitely need to be familiar with this API, Language Integrated Query ([LINQ][linq]) is available for many tasks, is even more powerful and widely used and has the advantage of providing a consistent interface across library collections, third-party collections and your own classes. See (TODO cross-ref-tba).
 
diff --git a/concepts/namespaces/about.md b/concepts/namespaces/about.md
index 828f04fd47..d9e0ead9d3 100644
--- a/concepts/namespaces/about.md
+++ b/concepts/namespaces/about.md
@@ -22,7 +22,7 @@ According to the [official documentation][namespaces] namespaces have two princi
 
 Namespaces are used widely by the base class library (BCL) to organize its functionality.
 
-#### References to namespaced types
+## References to namespaced types
 
 Types enclosed in namespaces are referred to outside the namespace by prefixing the type name with the dot syntax. Alternatively, and more usually, you can place a `using` directive at the top of the file (or within a namespace) and any types in the imported namespace can be used without the prefix. Within the same namespace there is no need to qualify type names.
 
@@ -68,13 +68,13 @@ This [article][using] clearly explains the ways in which the `using` directive c
 - `using static`: avoid having to qualify members with types (a good example is `Math.Max()`).
 - `using MyAlias = YourNamespace;`: substitute a more readable name for the namespace name.
 
-#### Clash of namespaces
+## Clash of namespaces
 
 .NET addresses the issue of two namespaces with the same name in different assemblies where there would be a clash of fully qualified identifier names (perhaps a scenario where multiple versions of an assembly are loaded). This issue is addressed with the [namespace alias qualifier][namespace-alias-qualifier] and the [extern alias][extern-alias].
 
 One reason to raise this fairly niche topic is because of its use of the [`::` operator][dot-dot-operator]. You will often see the qualifier `global::` prefixing namespaces, particularly in generated code. The intention here is to avoid a potential clash with some nested namespace or class name. By prefixing a namespace with `global::` you ensure that a top-level namespace is selected.
 
-#### Note for Java developers
+## Note for Java developers
 
 When comparing with the `import` of Java `packages` some differences and similarities should be noted:
 
diff --git a/concepts/nested-types/about.md b/concepts/nested-types/about.md
index 50748f1c74..ce5f848bb5 100644
--- a/concepts/nested-types/about.md
+++ b/concepts/nested-types/about.md
@@ -15,7 +15,7 @@ var outer = new Outer();
 var inner = new Outer.CInner();
 ```
 
-#### Access levels
+## Access levels
 
 Access levels can be applied to the inner types. For example if a class is `private` then it cannot be seen outside of the enclosing type's scope and of course instances cannot be seen or used outside the scope.
 
@@ -55,7 +55,7 @@ outer.Inner.Interesting
 // => 1729
 ```
 
-#### Prevent independent instantiation
+## Prevent independent instantiation
 
 There is a pattern to prevent an instantiable type being created outside the enclosing type. You expose a public interface but keep the implementing class private.
 
@@ -97,7 +97,7 @@ outer.Inner.DoSomething();
 // NOT var inner = new Outer.Inner(outer);
 ```
 
-#### Note for Java developers
+## Note for Java developers
 
 C#'s nested classes are a cross between Java's static nested classes and inner classes. In C# private members of the enclosing class are in scope for members of the nested class but there is no special syntax for instantiating them and linking them to an instance of the enclosing class. You have to use some variation of the pattern illustrated in the examples above.
 
diff --git a/concepts/operator-overloading/about.md b/concepts/operator-overloading/about.md
index 2ac3a4d5af..2229af2275 100644
--- a/concepts/operator-overloading/about.md
+++ b/concepts/operator-overloading/about.md
@@ -72,7 +72,7 @@ You should note that you cannot create operators from symbols that are not part
 
 Note that the order of parameters is important where they differ in type. In the above example code `pt * 10m` is a legal expression whereas `10m * pt` will not compile.
 
-#### Reference
+## Reference
 
 This documentation of [operator overloading][operator-overloading] details the syntax.
 
diff --git a/concepts/parameters/about.md b/concepts/parameters/about.md
index 463db3522a..dc433aa09b 100644
--- a/concepts/parameters/about.md
+++ b/concepts/parameters/about.md
@@ -74,7 +74,7 @@ Note that `optional parameters` and `named arguments` are discussed in the `meth
 
 The related topics of [`ref local`][ref-local] and [`ref return`][ref-return] are discussed elsewhere.
 
-### Stack Allocations
+## Stack Allocations
 
 The rules regarding parameters and their modifiers are sufficiently straightforward that you can take them at face value and understand them at their level of abstraction. However, if you are interested in the underlying mechanisms and why these keywords may make a performance difference, at least in the case of `struct`s, then you could start with this [_Wikipedia article_][calling-conventions], noting that C# uses `stdcall` on x86/64.
 
diff --git a/concepts/properties/introduction.md b/concepts/properties/introduction.md
index c5706faf8c..bfc75d4d49 100644
--- a/concepts/properties/introduction.md
+++ b/concepts/properties/introduction.md
@@ -20,7 +20,7 @@ accessor and vice versa. A property doesn't have to have both accessors, it can
 
 The basic syntax to express properties can take two forms:
 
-#### Field/Expression Backed Properties:
+## Field/Expression Backed Properties:
 
 ```csharp
 private int myField;
@@ -31,7 +31,7 @@ public int MyProperty
 }
 ```
 
-#### Auto-implemented Properties
+## Auto-implemented Properties
 
 ```
 public int MyProperty { get; private set; } = 42;
diff --git a/concepts/randomness/about.md b/concepts/randomness/about.md
index 6091b05a3b..09b6e3e1f8 100644
--- a/concepts/randomness/about.md
+++ b/concepts/randomness/about.md
@@ -28,7 +28,7 @@ You may see documentation discouraging the use of seedless constructors. This mo
 
 You are advised not to use `System.Random` for crypto or security. See this [provider][crypto-provider] and this [number generator][crypto-rng].
 
-##### Thread safety
+## Thread safety
 
 When applied in the context of library APIs "not thread safe" is simply shorthand for saying that, if you are likely to access instances of the class through multiple concurrent [threads][threading], you should provide your own thread synchronization mechanisms or, in the case of collections, look at the possibility of using a concurrent version of the class. In the absence of these precautions, [race conditions][so-race-conditions] are likely to occur. If your code base does not use multiple threads, and is not likely to, then this warning is of little concern.
 
diff --git a/concepts/regular-expressions/about.md b/concepts/regular-expressions/about.md
index 2827488151..e97e04edcf 100644
--- a/concepts/regular-expressions/about.md
+++ b/concepts/regular-expressions/about.md
@@ -4,7 +4,7 @@ The .NET base class libraries provide the [`Regex`][regex] class for processing
 
 See this [article][regex-comparison] for a comparison of C# with other flavours of regular expressions.
 
-#### Capture Groups
+## Capture Groups
 
 One aspect to consider is that of capture groups which return parts of the text matching various parts of the regex pattern. The approach to capture groups needs getting used to. See this [documentation][capture].
 
@@ -26,7 +26,7 @@ Caveats:
 - `Groups[0]` appears to relate to the entire match.
 - `Groups[].Value` is almost certainly what you are interested in. Individual captures (other than `Caputures[0]`) appear to be for intended for diagnostic purposes if they are present.
 
-#### Regex Options
+## Regex Options
 
 Familiarise yourself with [`RegexOptions`][regex-options].
 
diff --git a/concepts/resource-cleanup/about.md b/concepts/resource-cleanup/about.md
index ff47c44ac8..beec8981b6 100644
--- a/concepts/resource-cleanup/about.md
+++ b/concepts/resource-cleanup/about.md
@@ -54,7 +54,7 @@ public class Activity : IDisposable
 
 The `IDisposable` interface may be useful even where no unmanaged resources are in the mix. Say you have a long-lived object which requires short-lived objects to register themselves with it and then unregister when they are no longer required. Implementing `IDisposable` on the short-lived object puts a developer using that class on notice that `Dispose()` needs to be called at the end of the short-lived object's life.
 
-#### Dispose pattern
+## Dispose pattern
 
 You will see references in the documentation to the [dispose pattern][dispose-pattern]. The _dispose pattern_ includes calling `Dispose()` from a class's [finalizer][finalizer] and ensuring that disposal of resources in base classes is handled correctly. The _dispose pattern_ is dealt with in a later exercise.
 
diff --git a/concepts/resource-lifetime/about.md b/concepts/resource-lifetime/about.md
index 8e49ae67f1..cd1bf67dbb 100644
--- a/concepts/resource-lifetime/about.md
+++ b/concepts/resource-lifetime/about.md
@@ -61,15 +61,15 @@ catch (Exception)
 
 The rules related to how the `using` keyword can be used and with instances of what sort of types are detailed [here][using-statement].
 
-#### Note for Java Developers
+## Note for Java Developers
 
 Java developers may recognize this as an analog of the [_automatic resource management_][automatic-resource-management] mechanism introduced in Java 7. They are very similar. Java's syntax, which repurposes `try` has the advantage of incorporating `catch` blocks more naturally than does C#'s `using`.
 
-#### Versions
+## Versions
 
 Note that the more flexible version of `using` where it does not have its own syntactic block was introduced in C# 8 so you may need to check if the code base you are working on is using C# 8 or later.
 
-#### Reference
+## Reference
 
 [using statement][using-statement] documentation describes how and when to use the `using` keyword.
 
diff --git a/concepts/string-formatting/about.md b/concepts/string-formatting/about.md
index 55379b98e3..e76470ab09 100644
--- a/concepts/string-formatting/about.md
+++ b/concepts/string-formatting/about.md
@@ -4,13 +4,13 @@ Mechanisms for formatting strings are many and various in C#/.NET: everything fr
 
 The two most common mechanisms for formatting strings are [string interpolation][string-interpolation] and [String.Format()][string-format]. The [`StringBuilder`][string-builder] (cross-ref-tba) class can also be used to build up a string if there is complexity such as multiple lines involved.
 
-#### Using `ToString()`
+## Using `ToString()`
 
 `System.Object()` from which all classes and structs inherit has a `ToString()` method. For example `new DateTime(2019, 5, 23).ToString()` will render "05/23/2019 00:00:00" (on a thread with US culture - [see below](#culture)). There are situations such as string concatenation where this default `ToString()` method may be invoked implicitly, `"" + new DateTime(2019, 5, 23)` gives the same result.
 
 In addition to the default `ToString()` method, types where formatting is an issue will have overloads which take a [_format string_](#bcl-formatters-and-format-strings) or even a [format provider][format-provider]. Notably in the BCL (Base Class Library) these are numbers, dates, enums and GUIDs.
 
-#### Composite Formatting
+## Composite Formatting
 
 `String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as a _format items_) and a variable number of arguments. The return value resolves each _format item_ using the corresponding argument and combines the resolved values with the fixed text.
 
@@ -25,7 +25,7 @@ This mechanism is technically known as [_composite formatting_][composite-format
 
 A fuller list of string producing methods that take advantage _composite formatting_ is given in this [article][composite-formatting].
 
-#### String Interpolation
+## String Interpolation
 
 Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{[,][:]}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism.
 
@@ -38,7 +38,7 @@ $"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
 // => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
 ```
 
-#### Format Items
+## Format Items
 
 The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_.
 
@@ -67,7 +67,7 @@ string.Format(
 
 There is both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format characters. "custom" in this context has nothing to do with the [`ICustomFormatter`][custom-formatter] interface which is used when developing your own custom formatters.
 
-#### BCL Formatters and Format Strings
+## BCL Formatters and Format Strings
 
 The Base Class Library (BCL) provides 2 formatters: `DateTimeFormatInfo` and `NumberFormatInfo` and 6 groups of format strings.
 
@@ -84,13 +84,13 @@ The various lists of _format strings_ are below:
 
 An attempt is made in the library to instill some consistency into _format strings_ (beyond the fact that they are represented as strings). This push for consistency is found in the standard strings. In reality as a developer you rarely care about the difference between standard and custom strings. Although it is a good idea, if you are implementing formatters for your own classes to echo the existing standard strings if your classes appear to call for it, you can pretty well ignore the difference.
 
-#### Culture
+## Culture
 
 Each thread of execution has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted by default with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_.
 
 `CultureInfo` implements the `IFormatProvider` interface which can be passed to certain overloads of `String.Format()`. This can be used to override the thread culture.
 
-#### Reference Material
+## Reference Material
 
 [string-interpolation]: https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/string-interpolation
 [string-interpolation-in-depth]: https://weblog.west-wind.com/posts/2016/Dec/27/Back-to-Basics-String-Interpolation-in-C#
diff --git a/concepts/string-formatting/introduction.md b/concepts/string-formatting/introduction.md
index 8f13762b90..e07fdb1311 100644
--- a/concepts/string-formatting/introduction.md
+++ b/concepts/string-formatting/introduction.md
@@ -2,7 +2,7 @@
 
 There are two principal mechanisms for formatting strings in C#/.NET. Use of `String.Format()` and string interpolation.
 
-### Composite Formatting
+## Composite Formatting
 
 `String.Format()` takes a string (referred to in the documentation as a _composite format_) comprising fixed text and placeholders (known in the documentation as format items), and a variable number of arguments. The return value resolves each format item using the corresponding argument and combines the resolved values with the fixed text.
 
@@ -13,7 +13,7 @@ string.Format("I had {0} bitcoins on {1}, the day I forgot my password.", 55.5,
 
 This mechanism is technically known as _composite formatting_.
 
-### String Interpolation
+## String Interpolation
 
 Interpolated strings are prefixed with a `$` and include run-time expressions enclosed in braces. The format item has the following syntax: `$"{}"`. They do away with the need for a separate list of arguments. The result is functionally equivalent to the `String.Format()` mechanism.
 
@@ -24,7 +24,7 @@ $"I had {loadsOf} bitcoins on {thatDay}, the day I forgot my password."
 // => "I had 55.5 bitcoins on 2/25/2010 00:00:00, the day I forgot my password." - US settings
 ```
 
-### Format Items
+## Format Items
 
 The text in braces, placeholders in the case of the composite format and interpolated expressions in the case of string interpolation is known as a _format item_.
 
@@ -52,7 +52,7 @@ string.Format(
 
 There are both standard and custom formatting for both numbers and dates. There is no vital difference between _custom_ and _standard_ except that you have a chance to compose custom format strings out of format letters.
 
-### Culture
+## Culture
 
 Each thread has a default culture `Thread.CurrentThread.CurrentCulture` encapsulated in an instance of `CultureInfo`. The thread's culture determines how dates and numbers are formatted with respect to regional variations such as the difference in conventional date format between the UK _DD/MM/YYYY_ and the US _MM/DD/YYYY_.
 
diff --git a/concepts/structs/about.md b/concepts/structs/about.md
index 353bfc1648..9655f3292c 100644
--- a/concepts/structs/about.md
+++ b/concepts/structs/about.md
@@ -44,7 +44,7 @@ There are a couple of things that you will come up against (and about which the
 
 As a result of points 1 and 3 above there is no way for the developer of a `struct` to prevent invalid instances from coming into existence.
 
-#### Common structs
+## Common structs
 
 You will see from the documentation that there is a close relationship between primitives and structs. See [`Int32/int]`][int32], for an example. A more conventional example of a`struct`is the type [`TimeSpan`][time-span].
 
@@ -52,7 +52,7 @@ Instances of `TimeSpan` behave much like numbers with comparison operators like
 
 One thing to note about `TimeSpan` is that it implements a number of interfaces e.g. `IComparable`. Although `struct`s cannot be derived from other `struct`s they can implement interfaces.
 
-#### Equality
+## Equality
 
 Equality testing for `struct`s can often be much simpler than that for `class`s as it simply compares fields for equality by default. There is no need to override `object.Equals()` (or `GetHashCode()`). Remember that if you are relying on `Object.GetHashCode()` you must still ensure that the fields involved in generating the hash code (i.e. all the fields) must not change while a hashed collection is use. Effectively, this means that structs used in this way should be immutable. See (TODO cross-ref-tba).
 
@@ -79,7 +79,7 @@ public override int GetHashCode()
 }
 ```
 
-#### General
+## General
 
 - [structs][structs]: introduction to structs.
 - [class-or-struct][class-or-struct]: lists the guidelines for choosing between a struct and class.
diff --git a/concepts/tuples/about.md b/concepts/tuples/about.md
index 6860b8673e..c72bbe1ba2 100644
--- a/concepts/tuples/about.md
+++ b/concepts/tuples/about.md
@@ -52,7 +52,7 @@ bool result = estimateA == estimateB;
 
 This [introduction][tuples] shows how to define and use tuples.
 
-### Naming
+## Naming
 
 Field names `Item1` etc. do not make for readable code. There are 3 ways to
 provide names to the fields a) in the type declaration or b) in the expression that
@@ -75,7 +75,7 @@ Don't try to be too clever with the naming mechanism. It is really just syntacti
 sugar. For example, you cannot change the names of a tuple when you assign to it
 from another tuple.
 
-### Deconstruction
+## Deconstruction
 
 Sometimes it is convenient to take a tuple and assign the fields to multiple variables
 and initialize them if appropriate.
@@ -89,7 +89,7 @@ return ultimateQuestion;
 // => 42
 ```
 
-### Field Assignment
+## Field Assignment
 
 The fields of tuples can be individually assigned to.
 However, given the trend in C# towards immutability this
@@ -104,7 +104,7 @@ tpl.Item2 = "even worse";
 // => (1, "even worse";
 ```
 
-### Background
+## Background
 
 The tuples we are discussing should not be confused with [`System.Tuple`][system-tuple]
 which will probably be found only in legacy code bases.
@@ -119,7 +119,7 @@ unlikely to be of much interest, most of the time, to most people. Unfortunately
 documentation on "tuples" including Microsoft's own is liberally sprinkled with references
 to `System.ValueTuple`. It is probably safe to skate over such references.
 
-### Other Uses and Limitations
+## Other Uses and Limitations
 
 Pattern matching is a particularly productive use for tuples. This
 is covered in a later exercise.
diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md
index fe9b80184c..652209e938 100644
--- a/docs/INSTALLATION.md
+++ b/docs/INSTALLATION.md
@@ -1,6 +1,6 @@
 # Installation
 
-### Installing .NET Core
+## Installing .NET Core
 
 The C# track is built on top of the [.NET Core](https://www.microsoft.com/net/core/platform) platform, which runs on Windows, Linux and macOS. To build .NET Core projects, you can use the .NET Core Command Line Interface (CLI). This CLI is part of the .NET Core SDK, which you can install by following the [installation instructions](https://www.microsoft.com/net/download/core). Note: the C# track requires SDK version 3.0 or greater.
 
@@ -12,7 +12,7 @@ dotnet --version
 
 If the output is a version greater than or equal to `3.0.100`, the .NET Core SDK has been installed succesfully.
 
-### Using an IDE
+## Using an IDE
 
 If you want a more full-featured editing experience, you probably want to to use an IDE. These are the most popular IDE's that support building .NET Core projects:
 
diff --git a/docs/LEARNING.md b/docs/LEARNING.md
index f179b5290c..eb4b873aa4 100644
--- a/docs/LEARNING.md
+++ b/docs/LEARNING.md
@@ -1,11 +1,11 @@
 # Learning C# 
 
-### Websites
+## Websites
 
 * The [official C# documentation](https://docs.microsoft.com/en-us/dotnet/articles/csharp/) has great content on a wide variety of subjects, including [tutorials](https://docs.microsoft.com/en-us/dotnet/articles/csharp/tutorials/index) and a [tour of the language](https://docs.microsoft.com/en-us/dotnet/articles/csharp/tour-of-csharp/index).
 * [Learn C#](http://www.learncs.org/) is an interactive, in-browser tutorial that introduces you to the core concepts of programming in C#.
 
-### Videos
+## Videos
 
 * [C# 101](https://www.youtube.com/playlist?list=PLdo4fOcmZ0oVxKLQCHpiUWun7vlJJvUiN) The concepts and syntax of the C# programming language with live coding demos.
 * [.NET Core 101](https://www.youtube.com/playlist?list=PLdo4fOcmZ0oWoazjhXQzBKMrFuArxpW80) Ins and outs of "What is .NET" and how to publish your very first application.
@@ -13,7 +13,7 @@
 * [C# Fundamentals for Absolute Beginners](https://mva.microsoft.com/en-US/training-courses/c-fundamentals-for-absolute-beginners-16169?l=Lvld4EQIC_2706218949) is a great way to get to know C#.
 * [PluralSight](https://www.pluralsight.com/) has several [great](https://www.pluralsight.com/courses/csharp-6-from-scratch) [introduction](https://www.pluralsight.com/courses/c-sharp-fundamentals-with-visual-studio-2015) [courses](http://www.pluralsight.com/courses/csharp-best-practices-improving-basics). The downside: PluralSight is a paid service, but you can request a [free trial](https://www.pluralsight.com/pricing).
 
-### Books
+## Books
 * [C# 6.0 in a Nutshell](https://www.amazon.com/C-6-0-Nutshell-Definitive-Reference/dp/1491927062/)
 * [C# 5.0 Unleashed](https://www.amazon.com/C-5-0-Unleashed-Bart-Smet/dp/0672336901/)
 * [C# in Depth](https://www.amazon.com/dp/161729134X/)
diff --git a/docs/RESOURCES.md b/docs/RESOURCES.md
index 0b001f8c77..e499142810 100644
--- a/docs/RESOURCES.md
+++ b/docs/RESOURCES.md
@@ -1,28 +1,28 @@
 # Recommended Learning Resources
 
-### Blogs
+## Blogs
 
 - The official [.NET blog](https://blogs.msdn.microsoft.com/dotnet/) has lots of interesting C# articles, ranging from beginner to expert difficulty.
 - Scott Hanselman's [blog](http://www.hanselman.com/blog/) is an active, well written blog on a wide variety of C# and .NET related subjects.
 - Eric Lippert's [Fabulous adventures in coding](https://ericlippert.com/) is a brilliant C# blog, although his subjects are usually quite advanced.
 - The [C#/.NET Little Wonders & Little Pitfalls](http://geekswithblogs.net/BlackRabbitCoder/archive/2015/04/02/c.net-little-wonders-amp-little-pitfalls-the-complete-collection.aspx) posts by James Michael Hare contains some fantastic posts on less known C# features.
 
-### Social media
+## Social media
 
 - [StackOverflow](http://stackoverflow.com/questions/tagged/c%23) can be used to search for your problem and see if it has been answered already. You can also ask and answer questions.
 - [/r/csharp](https://www.reddit.com/r/csharp) is the C# subreddit.
 - [@dotnet](https://twitter.com/DotNet) is the official .NET Twitter account.
 - [Gitter](https://gitter.im/exercism/xcsharp) is the C# Gitter room, go here to get support and ask questions related to the C# track.
 
-### Videos
+## Videos
 
 - In [On .NET](https://www.youtube.com/watch?v=GpLU0UdcGic&list=PL4Sf58qFxdyQuzB1mH5kln_otKpsIuoCO), Bertrand Le Roy interviews people on a wide variety of C#/.NET related subjects.
 - There are several great [C# courses](https://www.pluralsight.com/search?q=*&categories=course&roles=software-development%7C&subjects=c%23) on PluralSight. The downside: PluralSight is a paid service, but you can request a [free trial](https://www.pluralsight.com/pricing).
 
-### Podcasts
+## Podcasts
 
 - [.NET Rocks](https://www.dotnetrocks.com/) is a very nice .NET podcast with great content.
 
-### Books
+## Books
 
 - [Expert C# 5.0](http://www.apress.com/us/book/9781430248606)
diff --git a/exercises/concept/faceid-2/.docs/hints.md b/exercises/concept/faceid-2/.docs/hints.md
index 023d4a2f00..0c6a7c737d 100644
--- a/exercises/concept/faceid-2/.docs/hints.md
+++ b/exercises/concept/faceid-2/.docs/hints.md
@@ -1,6 +1,6 @@
 # Hints
 
-### General
+## General
 
 - [Equality][equality]: how equality comparisons work in C#, including reference- and value type equality.
 - [HashCode][hash-code]: how to create and combine hash codes
diff --git a/exercises/concept/football-match-reports/.docs/hints.md b/exercises/concept/football-match-reports/.docs/hints.md
index 7d635ece83..bbd812bdfc 100644
--- a/exercises/concept/football-match-reports/.docs/hints.md
+++ b/exercises/concept/football-match-reports/.docs/hints.md
@@ -2,19 +2,19 @@
 
 [switch statement][switch-statement] documentation provides an introduction to `switch` statements.
 
-### 1. Output descriptions of the players based on their shirt number
+## 1. Output descriptions of the players based on their shirt number
 
 - The [`break`][break] statement is useful.
 
-### 2. Raise an alert if an unknown shirt number is encountered.
+## 2. Raise an alert if an unknown shirt number is encountered.
 
 - The [`default`][default] statement is useful.
 
-### 3. Extend the coverage to include off field activity
+## 3. Extend the coverage to include off field activity
 
 - [Pattern matching on types][switch-pattern-matching] is the key to this task.
 
-### 4. Where the manager has a name available we want that output instead of "the manager"
+## 4. Where the manager has a name available we want that output instead of "the manager"
 
 - See this [documentation][switch-when] for the `when` keyword.
 
diff --git a/exercises/concept/football-match-reports/.docs/instructions.md b/exercises/concept/football-match-reports/.docs/instructions.md
index 6bacd19e38..b10f7bd46a 100644
--- a/exercises/concept/football-match-reports/.docs/instructions.md
+++ b/exercises/concept/football-match-reports/.docs/instructions.md
@@ -2,7 +2,7 @@
 
 You are developing a system to help the staff of a football/soccer club's web site report on matches. Data is received from a variety of sources and piped into a single stream after being cleaned up.
 
-### 1. Output descriptions of the players based on their shirt number
+## 1. Output descriptions of the players based on their shirt number
 
 The team only ever plays a 4-3-3 formation and has never agreed with the 1965 change to the rules allowing for substitutions, never mind enlarged squads.
 
@@ -26,11 +26,11 @@ PlayAnalyzer.AnalyzeOnField(10);
 // => "striker"
 ```
 
-### 2. Raise an alert if an unknown shirt number is encountered.
+## 2. Raise an alert if an unknown shirt number is encountered.
 
 Modify the `PlayAnalyzer.AnalyzeOnField()` method to throw an `ArgumentException` when a shirt number outside the range 1-11 is processed.
 
-### 3. Extend the coverage to include off field activity
+## 3. Extend the coverage to include off field activity
 
 Implement the `PlayAnalyzer.AnalyzeOffField()` method to output description of activities and characters around the field of play.
 
@@ -50,7 +50,7 @@ PlayAnalyzer.AnalyzeOffField(new Manager());
 // => "the manager"
 ```
 
-### 4. Where the manager has a name available we want that output instead of "the manager"
+## 4. Where the manager has a name available we want that output instead of "the manager"
 
 Modify the `PlayAnalyzer.AnalyzeOffField()` method to output any name such as "Jürgen Klopp" if there is one. If there is no name then the `Manager.Name` property is guaranteed to be an empty string rather than null.
 
diff --git a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
index 714616a7a8..b85636f08f 100644
--- a/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
+++ b/exercises/concept/hyper-optimized-telemetry/.docs/introduction.md
@@ -31,6 +31,6 @@ short s = 42;
 uint ui = (uint)s;
 ```
 
-#### Bit conversion
+## Bit conversion
 
 The `BitConverter` class provides a convenient way of converting integer types to and from arrays of bytes.
diff --git a/exercises/concept/international-calling-connoisseur/.docs/hints.md b/exercises/concept/international-calling-connoisseur/.docs/hints.md
index bf75d75a1b..5152dba06a 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/hints.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/hints.md
@@ -1,48 +1,48 @@
 # Hints
 
-### 1. Create a new dictionary
+## 1. Create a new dictionary
 
 A dictionary is like any other class. You simply 'new' it to create an empty instance.
 
-### 2. Create a pre-populated dictionary
+## 2. Create a pre-populated dictionary
 
 Although it's possible to populate a dictionary by repeatedly adding items, dictionaries can be initialized statically.
 
 See [this article][dictionary_static_initialization].
 
-### 3. Add a country to an empty dictionary
+## 3. Add a country to an empty dictionary
 
 See [Add][dictionary_add]. Pass in the dictionary returned by task 1 as a parameter.
 
-### 4. Add a country to an existing dictionary
+## 4. Add a country to an existing dictionary
 
 There is no substantial difference between adding an item to an empty or initialized dictionary. Pass in the dictionary returned by task 2 as a parameter.
 
-### 5. Get the country name matching a country Code
+## 5. Get the country name matching a country Code
 
 See [this article][dictionary_item].
 
-### 6. Attempt to get country name for a non-existent country code
+## 6. Attempt to get country name for a non-existent country code
 
 You need to [detect][dictionary_contains_key] whether the country is present in the dictionary.
 
-### 7. Attempt to get country name for a non-existent country code
+## 7. Attempt to get country name for a non-existent country code
 
 You can combine what you've learnt in Tasks 5 and 6 to solve this one.
 
-### 8. Update a country name
+## 8. Update a country name
 
 Again [this article][dictionary_item] applies.
 
-### 9. Attempt to ypdate name of country that is not in the dictionary
+## 9. Attempt to ypdate name of country that is not in the dictionary
 
 This is very similar to task 7.
 
-### 10. Remove a country from the dictionary
+## 10. Remove a country from the dictionary
 
 See [this article][dictionary_remove].
 
-### 11. Find the country with the longest name
+## 11. Find the country with the longest name
 
 See the [values collection][dictionary_values], [string length][string_length] and [foreach][foreach].
 
diff --git a/exercises/concept/international-calling-connoisseur/.docs/instructions.md b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
index 346a15a185..15cc1bc679 100644
--- a/exercises/concept/international-calling-connoisseur/.docs/instructions.md
+++ b/exercises/concept/international-calling-connoisseur/.docs/instructions.md
@@ -6,7 +6,7 @@ The dictionary uses an integer for its keys (the dialing code) and a string (cou
 
 You have 9 tasks which involve the `DialingCodes` static class.
 
-### 1. Create a new dictionary
+## 1. Create a new dictionary
 
 Implement the (static) method `DialingCodes.GetEmptyDictionary()` that returns an empty dictionary.
 
@@ -15,7 +15,7 @@ DialingCodes.GetEmptyDictionary();
 // => empty dictionary
 ```
 
-### 2. Create a pre-populated dictionary
+## 2. Create a pre-populated dictionary
 
 There exists a pre-populated dictionary which contains the following 3 dialing codes: "United States of America" which has a code of 1, "Brazil" which has a code of 55 and "India" which has a code of 91. Implement the (static) `DialingCodes.GetExistingDictionary()` method to return the pre-populated dictionary:
 
@@ -24,7 +24,7 @@ DialingCodes.GetExistingDictionary();
 // => 1 => "United States of America", 55 => "Brazil", 91 => "India"
 ```
 
-### 3. Add a country to an empty dictionary
+## 3. Add a country to an empty dictionary
 
 Implement the (static) method `DialingCodes.AddCountryToEmptyDictionary()` that creates a dictionary and adds a dialing code and associated country name to it.
 
@@ -33,7 +33,7 @@ DialingCodes.AddCountryToEmptyDictionary(44, "United Kingdom");
 // => 44 => "United Kingdom"
 ```
 
-### 4. Add a country to an existing dictionary
+## 4. Add a country to an existing dictionary
 
 Implement the (static) method `DialingCodes.AddCountryToExistingDictionary()` that adds a dialing code and associated country name to a non-empty dictionary.
 
@@ -43,7 +43,7 @@ DialingCodes.AddCountryToExistingDictionary(DialingCodes.GetExistingDictionary()
 // => 1 => "United States of America", 44 => "United Kingdom", 55 => "Brazil", 91 => "India"
 ```
 
-### 5. Get the country name matching a dialing code
+## 5. Get the country name matching a dialing code
 
 Implement the (static) method `DialingCodes.GetCountryNameFromDictionary()` that takes a dialing code and returns the corresponding country name. If the dialing code is not contained in the dictionary then an empty string is returned.
 
@@ -57,7 +57,7 @@ DialingCodes.GetCountryNameFromDictionary(
 // => string.Empty
 ```
 
-### 6. Check that a country exists in the dictionary
+## 6. Check that a country exists in the dictionary
 
 Implement the (static) method `DialingCodes.CheckCodeExists()` to check whether a dialing code exists in the dictionary.
 
@@ -66,7 +66,7 @@ DialingCodes.CheckCodeExists(DialingCodes.GetExistingDictionary(), 55);
 // => true
 ```
 
-### 7. Update a country name
+## 7. Update a country name
 
 Implement the (static) method `DialingCodes.UpdateDictionary()` which takes a dialing code and replaces the corresponding country name in the dictionary with the country name passed as a parameter. If the dialing code does not exist in the dictionary then the dictionary remains unchanged.
 
@@ -80,7 +80,7 @@ DialingCodes.UpdateDictionary(
 // 1 => "United States of America", 55 => "Brazil", 91 => "India"
 ```
 
-### 8. Remove a country from the dictionary
+## 8. Remove a country from the dictionary
 
 Implement the (static) method `DialingCodes.RemoveCountryFromDictionary()` that takes a dialing code and will remove the corresponding record, dialing code + country name, from the dictionary.
 
@@ -90,7 +90,7 @@ DialingCodes.RemoveCountryFromDictionary(
 // => 1 => "United States of America", 55 => "Brazil"
 ```
 
-### 9. Find the country with the longest name
+## 9. Find the country with the longest name
 
 Implement the (static) method `DialingCodes.FindLongestCountryName()` which will return the name of the country with the longest name stored in the dictionary.
 
diff --git a/exercises/concept/parsing-log-files/.docs/hints.md b/exercises/concept/parsing-log-files/.docs/hints.md
index 9dcbb09d24..a6627a994e 100644
--- a/exercises/concept/parsing-log-files/.docs/hints.md
+++ b/exercises/concept/parsing-log-files/.docs/hints.md
@@ -3,23 +3,23 @@
 - [regular expressions][regular-expressions] documentation describes regexes and the flavour built into the .NET libraries.
 - [Regex][regex] documentation describing the built-in library class.
 
-### 1. Identify garbled log lines
+## 1. Identify garbled log lines
 
 - See [this discussion][ismatch] of matching.
 
-### 2. Split the log line
+## 2. Split the log line
 
 - [This][split] article shows an approach to splitting lines.
 
-### 3. Count the number of lines containing a password
+## 3. Count the number of lines containing a password
 
 - See [this discussion][multiple-matches] of multiple matches and [this][multi-line] on multi-line searches.
 
-### 4. Remove artifacts from log
+## 4. Remove artifacts from log
 
 - [This article][replace] shows how text can be replaced.
 
-### 5. List lines with extremely weak passwords so the guilty can be punished
+## 5. List lines with extremely weak passwords so the guilty can be punished
 
 - Capture groups are discussed [here][capture-groups].
 
diff --git a/exercises/concept/parsing-log-files/.docs/instructions.md b/exercises/concept/parsing-log-files/.docs/instructions.md
index ec8c196692..02e899891e 100644
--- a/exercises/concept/parsing-log-files/.docs/instructions.md
+++ b/exercises/concept/parsing-log-files/.docs/instructions.md
@@ -6,7 +6,7 @@ After a recent security review you have been asked to clean up the organization'
 
 All strings passed to the methods are guaranteed to be non-null and leading and without trailing spaces.
 
-### 1. Identify garbled log lines
+## 1. Identify garbled log lines
 
 You need some idea of how many log lines in your archive do not comply with current standards. You believe that a simple test reveals whether a log line is valid. To be considered valid a line should begin with one of the following strings:
 
@@ -29,7 +29,7 @@ lp.IsMatch("[BOB] Any old text");
 // => false
 ```
 
-### 2. Split the log line
+## 2. Split the log line
 
 A new team has joined the organization, and you find their log files are using a strange separator for "fields". Instead of something sensible like a colon ":" they use a string such as "<--->" or "<=>" (because it's prettier) in fact any string that has a first character of "<" and a last character of ">" and any combination of the following characters "^", "\*", "=" and "-" in between.
 
@@ -41,7 +41,7 @@ lp.SplitLogLine("Section 1<===>Section 2<^-^>Section 3");
 // => {"Section 1", "Section 2", "Section 3"}
 ```
 
-### 3. Count the number of lines containing a password
+## 3. Count the number of lines containing a password
 
 A log line is considered to contain a password if it contains the literal string "password" followed by a space and then a word (the actual password).
 
@@ -64,7 +64,7 @@ lp.CountQuotedPasswords(lines);
 // => 2
 ```
 
-### 4. Remove artifacts from log
+## 4. Remove artifacts from log
 
 You have found that some upstream processing of the logs has been scattering the text "end-of-line" followed by a line number (without an intervening space) throughout the logs.
 
@@ -80,7 +80,7 @@ lp.RemoveEndOfLineText("[INF] end-of-line23033 Network Failure end-of-line27");
 // => "[INF]  Network Failure "
 ```
 
-### 5. List lines with extremely weak passwords so the guilty can be punished
+## 5. List lines with extremely weak passwords so the guilty can be punished
 
 Before expunging the passwords from the file we need to list any instances where passwords begin with the text "password".
 
diff --git a/exercises/concept/phone-number-analysis/.docs/hints.md b/exercises/concept/phone-number-analysis/.docs/hints.md
index 2bb9cfa8f2..17f0df32a8 100644
--- a/exercises/concept/phone-number-analysis/.docs/hints.md
+++ b/exercises/concept/phone-number-analysis/.docs/hints.md
@@ -1,14 +1,14 @@
 # Hints
 
-### General
+## General
 
 - [Tuples][tuples]: shows how to define and use tuples.
 
-### 1. Analyze a phone number
+## 1. Analyze a phone number
 
 - Tuples are passed as a [return value][tuples-return].
 
-### 2. Detect if a phone number is fake prefix code (555)
+## 2. Detect if a phone number is fake prefix code (555)
 
 - You can extract the value of a field with the same sort of dot syntax as you employ with `struct`s or `class`s.
 
diff --git a/exercises/concept/phone-number-analysis/.docs/instructions.md b/exercises/concept/phone-number-analysis/.docs/instructions.md
index 7c08a8eca3..b2af31e8e5 100644
--- a/exercises/concept/phone-number-analysis/.docs/instructions.md
+++ b/exercises/concept/phone-number-analysis/.docs/instructions.md
@@ -7,7 +7,7 @@ You are asked to implement 2 features.
 Phone numbers passed to the routines are guaranteed to be in the form
 NNN-NNN-NNNN e.g. 212-515-9876 and non-null.
 
-### 1. Analyze a phone number
+## 1. Analyze a phone number
 
 Your analysis should return 3 pieces of data
 
@@ -22,7 +22,7 @@ PhoneNumber.Analyze("631-555-1234");
 // => (false, true, "1234")
 ```
 
-### 2. Detect if a phone number has a fake prefix code (555)
+## 2. Detect if a phone number has a fake prefix code (555)
 
 Implement the (static) method `PhoneNumber.IsFake()` to detect whether the phone number is fake using the phone number info produced in task 1.
 
diff --git a/exercises/concept/roll-the-die/.docs/hints.md b/exercises/concept/roll-the-die/.docs/hints.md
index 9d90d878ef..2a7f01790c 100644
--- a/exercises/concept/roll-the-die/.docs/hints.md
+++ b/exercises/concept/roll-the-die/.docs/hints.md
@@ -1,14 +1,14 @@
 # Hints
 
-### General
+## General
 
 This [article][system-random] is an excellent introduction to the subject.
 
-### 1. Enable a wizards and warriors player to roll a die.
+## 1. Enable a wizards and warriors player to roll a die.
 
 This [article][random-integers] explains how to generate integers.
 
-### 2. Players need their strength. Provide a means to generate spell strength
+## 2. Players need their strength. Provide a means to generate spell strength
 
 This [article][random-reals] explains how to generate real numbers.
 
diff --git a/exercises/concept/squeaky-clean/.docs/hints.md b/exercises/concept/squeaky-clean/.docs/hints.md
index 5113a8ef9f..2d6d30b5f2 100644
--- a/exercises/concept/squeaky-clean/.docs/hints.md
+++ b/exercises/concept/squeaky-clean/.docs/hints.md
@@ -1,6 +1,6 @@
 # Hints
 
-### 1. Replace any spaces encountered with underscores
+## 1. Replace any spaces encountered with underscores
 
 - [This tutorial][chars-tutorial] is useful.
 - [Reference documentation][chars-docs] for `char`s is here.
@@ -9,15 +9,15 @@
 - See [this method][iswhitespace] for detecting spaces. Remember it is a static method.
 - `char` literals are enclosed in single quotes.
 
-### 2. Replace control characters with the upper case string "CTRL"
+## 2. Replace control characters with the upper case string "CTRL"
 
 - See [this method][iscontrol] to check if a character is a control character.
 
-### 3. Convert kebab-case to camel-case
+## 3. Convert kebab-case to camel-case
 
 - See [this method][toupper] to convert a character to upper case.
 
-### 4. Omit Greek lower case letters
+## 4. Omit Greek lower case letters
 
 - `char`s support the default equality and comparison operators.
 
diff --git a/exercises/concept/squeaky-clean/.docs/instructions.md b/exercises/concept/squeaky-clean/.docs/instructions.md
index 1edfe325ae..a5e8443051 100644
--- a/exercises/concept/squeaky-clean/.docs/instructions.md
+++ b/exercises/concept/squeaky-clean/.docs/instructions.md
@@ -10,7 +10,7 @@ In all cases the input string is guaranteed to be non-null. If an empty string i
 
 Note that the caller should avoid calling the routine `Clean` with an empty identifier since such identifiers are ineffectual.
 
-### 1. Replace any spaces encountered with underscores
+## 1. Replace any spaces encountered with underscores
 
 Implement the (_static_) `Identifier.Clean()` method to replace any spaces with underscores. This also applies to leading and trailing spaces.
 
@@ -19,7 +19,7 @@ Identifier.Clean("my   Id");
 // => "my___Id"
 ```
 
-### 2. Replace control characters with the upper case string "CTRL"
+## 2. Replace control characters with the upper case string "CTRL"
 
 Modify the (_static_) `Identifier.Clean()` method to replace control characters with the upper case string `"CTRL"`.
 
@@ -28,7 +28,7 @@ Identifier.Clean("my\0Id");
 // => "myCTRLId",
 ```
 
-### 3. Convert kebab-case to camelCase
+## 3. Convert kebab-case to camelCase
 
 Modify the (_static_) `Identifier.Clean()` method to convert kebab-case to camelCase.
 
@@ -37,7 +37,7 @@ Identifier.Clean("à-ḃç");
 // => "àḂç"
 ```
 
-### 4. Omit Greek lower case letters
+## 4. Omit Greek lower case letters
 
 Modify the (_static_) `Identifier.Clean()` method to omit any Greek letters in the range 'α' to 'ω'.
 
diff --git a/exercises/concept/weighing-machine/.docs/introduction.md b/exercises/concept/weighing-machine/.docs/introduction.md
index c5706faf8c..bfc75d4d49 100644
--- a/exercises/concept/weighing-machine/.docs/introduction.md
+++ b/exercises/concept/weighing-machine/.docs/introduction.md
@@ -20,7 +20,7 @@ accessor and vice versa. A property doesn't have to have both accessors, it can
 
 The basic syntax to express properties can take two forms:
 
-#### Field/Expression Backed Properties:
+## Field/Expression Backed Properties:
 
 ```csharp
 private int myField;
@@ -31,7 +31,7 @@ public int MyProperty
 }
 ```
 
-#### Auto-implemented Properties
+## Auto-implemented Properties
 
 ```
 public int MyProperty { get; private set; } = 42;
diff --git a/exercises/practice/accumulate/.meta/hints.md b/exercises/practice/accumulate/.meta/hints.md
index 1d904012b4..1483e3982a 100644
--- a/exercises/practice/accumulate/.meta/hints.md
+++ b/exercises/practice/accumulate/.meta/hints.md
@@ -2,7 +2,7 @@
 
 To be more specific, you are not allowed to use any of the built-in [LINQ methods](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=netcore-2.1#methods).
 
-### Laziness test
+## Laziness test
 
 Since `accumulate` returns an `IEnumerable`, it's execution is deferred until `ToList()` it is called on it, which is tested with the `Accumulate_is_lazy` method
 
diff --git a/exercises/practice/etl/README.md b/exercises/practice/etl/README.md
index b4bf39b3bc..85f0fff2d8 100644
--- a/exercises/practice/etl/README.md
+++ b/exercises/practice/etl/README.md
@@ -2,7 +2,7 @@
 
 We are going to do the `Transform` step of an Extract-Transform-Load.
 
-### ETL
+## ETL
 
 Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so
 we're going to migrate this."
@@ -11,7 +11,7 @@ we're going to migrate this."
 once." That's then typically followed by much forehead slapping and
 moaning about how stupid we could possibly be.)
 
-### The goal
+## The goal
 
 We're going to extract some scrabble scores from a legacy system.
 
@@ -39,7 +39,7 @@ input letters:
 Your mission, should you choose to accept it, is to transform the legacy data
 format to the shiny new format.
 
-### Notes
+## Notes
 
 A final note about scoring, Scrabble is played around the world in a
 variety of languages, each with its own unique scoring table. For
diff --git a/exercises/practice/grep/README.md b/exercises/practice/grep/README.md
index ca25cbd16a..50b0eee934 100644
--- a/exercises/practice/grep/README.md
+++ b/exercises/practice/grep/README.md
@@ -33,7 +33,7 @@ hello
 hello again
 ```
 
-### Flags
+## Flags
 
 As said earlier, the `grep` command should also support the following flags:
 
diff --git a/exercises/practice/rest-api/README.md b/exercises/practice/rest-api/README.md
index 10868b1de3..f91fb67ef2 100644
--- a/exercises/practice/rest-api/README.md
+++ b/exercises/practice/rest-api/README.md
@@ -6,9 +6,9 @@ Four roommates have a habit of borrowing money from each other frequently, and h
 
 Your task is to implement a simple [RESTful API](https://en.wikipedia.org/wiki/Representational_state_transfer) that receives [IOU](https://en.wikipedia.org/wiki/IOU)s as POST requests, and can deliver specified summary information via GET requests.
 
-### API Specification
+## API Specification
 
-#### User object
+### User object
 ```json
 {
   "name": "Adam",
@@ -25,7 +25,7 @@ Your task is to implement a simple [RESTful API](https://en.wikipedia.org/wiki/R
 }
 ```
 
-#### Methods
+### Methods
 
 | Description | HTTP Method | URL | Payload Format | Response w/o Payload | Response w/ Payload |
 | --- | --- | --- | --- | --- | --- |
diff --git a/exercises/practice/spiral-matrix/README.md b/exercises/practice/spiral-matrix/README.md
index 534fe6e103..d7c2336817 100644
--- a/exercises/practice/spiral-matrix/README.md
+++ b/exercises/practice/spiral-matrix/README.md
@@ -6,7 +6,7 @@ The matrix should be filled with natural numbers, starting from 1
 in the top-left corner, increasing in an inward, clockwise spiral order,
 like these examples:
 
-###### Spiral matrix of size 3
+## Spiral matrix of size 3
 
 ```text
 1 2 3
@@ -14,7 +14,7 @@ like these examples:
 7 6 5
 ```
 
-###### Spiral matrix of size 4
+## Spiral matrix of size 4
 
 ```text
  1  2  3 4
diff --git a/exercises/practice/tournament/README.md b/exercises/practice/tournament/README.md
index 5568063136..a10b4f9561 100644
--- a/exercises/practice/tournament/README.md
+++ b/exercises/practice/tournament/README.md
@@ -25,7 +25,7 @@ A win earns a team 3 points. A draw earns 1. A loss earns 0.
 
 The outcome should be ordered by points, descending. In case of a tie, teams are ordered alphabetically.
 
-###
+##
 
 Input
 
diff --git a/reference/implementing-a-concept-exercise.md b/reference/implementing-a-concept-exercise.md
index 97a4fdc849..469a0b060a 100644
--- a/reference/implementing-a-concept-exercise.md
+++ b/reference/implementing-a-concept-exercise.md
@@ -95,11 +95,11 @@ How to create the files common to all tracks is described in the [how to impleme
 
 All C# code should be formatted using the [`dotnet format` tool][dotnet-format]. There are two ways to format your C# code:
 
-#### 1. Using a GitHub comment
+### 1. Using a GitHub comment
 
 If you add a comment to a GitHub PR that contains the text `/dotnet-format`, a GitHub workflow will format all C# documents in the PR using `dotnet format`. Any formatting changes made by `dotnet format` will automatically be committed to the PR's branch. This also works for forks that have [enabled maintainers to edit the fork's PR][allowing-fork-pr-changes] (which is the default).
 
-#### 2. Using a script
+### 2. Using a script
 
 Open a command prompt in the `language/csharp` directory and then run:
 
diff --git a/reference/out-of-scope.md b/reference/out-of-scope.md
index f3adedd24e..9fada2dbf7 100644
--- a/reference/out-of-scope.md
+++ b/reference/out-of-scope.md
@@ -14,26 +14,26 @@ Where material is covered under "Out of scope" in _design.md_
 for a particular exercise it should not be repeated here
 unless it is felt that the topic otherwise has insufficient prominence.
 
-### 3rd Party and Microsoft Libraries
+## 3rd Party and Microsoft Libraries
 
 - JSON.net
 - NodaTime
 - .NET Forms
 - WPF
 
-### Frameworks
+## Frameworks
 
 - .NET Framework
 - ASP.NET (Core)
 - Unity
 
-### Platform
+## Platform
 
 - .NET interop (e.g. with Visual Basic or F#)
 - NuGet
 - Project/solution files
 
-### Other
+## Other
 
 - File handling
 - Networking