diff --git a/api/learn/learn.go b/api/learn/learn.go index ffd2d46..7d181a8 100644 --- a/api/learn/learn.go +++ b/api/learn/learn.go @@ -79,7 +79,7 @@ func NewAPI(baseURL string, client api.Client, getPresignedPostUrl bool) (*APICl creds, err := apiClient.RetrieveCredentials(getPresignedPostUrl) if err != nil { return nil, fmt.Errorf( - "Could not retrieve credentials from Learn. Please reset your API token with this command: learn set --api_token=your-token-from-%s/api_token", baseURL, + "Could not retrieve credentials from Learn. Please reset your API token with this command: learn set --api_token=your-token-from-%s/api_token\n\n", baseURL, ) } diff --git a/app/cmd/embeds/walkthrough/01-example-unit/00-hello-world.md b/app/cmd/embeds/walkthrough/01-example-unit/00-hello-world.md new file mode 100644 index 0000000..95128c9 --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/00-hello-world.md @@ -0,0 +1,63 @@ +--- +Type: Lesson +UID: hello-world +--- + +# Hello World + +### !callout-info +If you just ran `learn preview 00-hello-world.md`, you’re now looking at a temporary preview of this file. + +Go back to the command line and run `learn preview .` to preview all example materials. + +Visit the new link and click on the 'Example Unit' to return to this page. +### !end-callout + +This file is written in markdown. You can change any part of it and run +``` +learn preview . +``` +to see your update. You may preview individual files by specifying them for faster previewing. This is the part of the recommended workflow when developing new content and modifying existing content. + +## Your Preview Cohort + +If you look at the URL Learn created where your content can be found, you'll notice a cohort id which belongs to you! Learn cohorts are where instructors and students come together to learn subjects and montior progress, but this cohort is just for your curriculum development. Content you preview will always attach itself to your preview cohort and remain there until your next preview. + +The urls are built using the file names in the project, so each time you preview the same project you can simply refresh the browser to see changes you have made. + +If you just ran `learn preview .` from the root of the walkthrough directory, you might notice new content in the side bar. This content is produced from the walkthrough files: +``` +├── 01-example-unit +│   ├── 00-hello-world.md +│   ├── 01-configuration.md +│   ├── 02-publishing.md +│   ├── 03-markdown-examples.md +│   ├── 04-challenges.md +│   ├── 05-checkpoint.md +``` + +* The 'Configuration' file explains how a repository can be organized into units of content. +* 'Publishing' shows you how to make your materials available for use in a cohort. +* Explore rendering options in 'Markdown Examples'. +* See how Learn enables inline checks for understanding with 'Challenge Examples'. +* Each unit can assess a student's understanding with 'Checkpoint Example'. + +## Generating Content + +The `learn` CLI tool can generate boilerplate markdown for challenges and other custom markdown content (like the callout above) with the command +``` +learn md +``` + +so for example, you can see how a callout markdown can be rendered in a content file with + +``` +learn md co -o +``` + +Try it now and compare it to the content of the `00-hello-world.md` file in your editor. The callout markdown you generated appears much like the callout at the top of the file. + +If you use the `-o` flag the content is sent to `STDOUT`, while the `-m` flag produces a minimal version of the content. + +Each lesson will explore different options with this command. + diff --git a/app/cmd/embeds/walkthrough/01-example-unit/01-configuration.md b/app/cmd/embeds/walkthrough/01-example-unit/01-configuration.md new file mode 100644 index 0000000..be3c644 --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/01-configuration.md @@ -0,0 +1,95 @@ +--- +# This is yaml frontmatter which will set values for a generated `autoconfig.yaml` file +# It is not displayed in Learn. +Type: Lesson # Options: Lesson, Checkpoint, Survey, Instructor, Resource +# Lesson is a normal content file +# Checkpoint is a test, which has special configuration options; limit one per unit +# Surveys hold a set of ungraded challenges, and are submitted all at once +# Instructor files are only visible to instructors +# Resources can be linked within content, but will not show up in the navigation side bar +UID: unique-identifier # can be set to any string, must be unique in the repository +# DefaultVisibility: hidden # Uncomment this line to default Lesson to hidden when used +--- + +# Configuration + +If look at this file in your preferred text editor, you'll see content at the top that is not displayed in Learn. This yaml frontmatter is used to set attributes on the content file for Learn. + +You can see an example header by running +``` +learn md fh -o +``` +from your command line. + +### !callout-info + +## Setting Title + +You'll notice the title is not configured in the front matter- it is always derived from the first h1 header in the content file. If none can be found, the file name defines the title. + +### !end-callout + +## Tracking configuration in a file + +After you ran `learn preview .` you'll see a new file in the root of the walkthrough directory named `autoconfig.yaml`. The yaml frontmatter at the top of each file sets the values for the `ContentFiles` key in the `autoconfig.yaml`. + +You can see the format and more information for configuration options by running +``` +learn md cfy -o +``` +from your command line. + +## Controlling Configuration from one file + +Each time the preview is created, the `autoconfig.yaml` file is overwritten. + +However, running `learn preview` or `learn publish` won't generate an `autoconfig.yaml` file if there is already a file named `config.yaml` at the root of the project. Both files are used to define content; `config.yaml` takes precedence over `autoconfig.yaml`, and the latter will rebuild itself on each `preview` or `publish`. + +Go ahead and change the `autoconfig.yaml` file to `config.yaml`, then comment out the `ContentFiles` entry that looks like +``` + - Type: Lesson + Path: /01-example-unit/01-configuration.md + UID: unique-identifier +``` +Then from the root of the project run `learn preview .` again. You'll notice that this content file is now missing! + +Delete the `config.yaml` file entirely, and run `learn preview .` again. It will recreate the `autoconfig.yaml` file again as no config file was discovered. + +## Controlling Unit attributes + +In the configuration file there is a single entry for `Standards`. When the autoconfig was generated, its attributes were read from the file `01-example-unit/description.yaml`. + +You can see an example `description.yaml` file by running +``` +learn md dsy -o +``` +from your command line. + +Each unit directory like `01-example-unit/` should have one `description.yaml` file. + +## Adding more Units + +Create a new Unit directory as a sibling to `01-example-unit/` and name it `02-my-unit/`. Populate it with a single markdown file called `00-playground.md`. From the root of the walkthrough + +``` +mkdir 02-my-unit/ +touch 02-my-unit/00-playground.md +``` + +Write the following contents to your new file: + +``` +--- +Type: Lesson +UID: playground +--- +# Playground + +Use this file to experiment! +``` + +Then run `learn preview .` again from the root of the walkthrough directory. Follow the link and notice that you now have _two_ units displayed in your preview. + +We never wrote a `description.yaml` file for our second unit! What did it display for the unit Title and Description? Try adding your own `description.yaml` file inside your `02-my-unit/` directory and change the settings as you see fit. Re-preview to see how Title and Description are now configured. + +Try renaming your new unit directory to `00-my-unit/` and preview again with `learn preview .` to see that the ordering diff --git a/app/cmd/embeds/walkthrough/01-example-unit/02-publishing.md b/app/cmd/embeds/walkthrough/01-example-unit/02-publishing.md new file mode 100644 index 0000000..cd03c81 --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/02-publishing.md @@ -0,0 +1,49 @@ +--- +Type: Lesson +UID: publishing +--- + +# Publishing + +In order to use curriculum content, it must be published in Learn under a 'block'. Each block represents one remote repository, and each block can have several released versions of curriculum. + +In this way curriculum development of blocks mirrors working on production software. Changes can be made in the repository until a new 'deployment' of curriculum is ready to be created from a single commit. + +Publishing 'deploys' a new release of curriculum content for that block at that commit SHA. Different branches of the same repository can be published to provide greater flexibility when delivering content. + +## Requirements + +In order to publish curriculum, the project must be in a remote git based version control system, and Learn must have permission to access the repository. + +Learn works with GitHub, Gitlab SaaS, and self hosted GitLab instances. Private repositories can be used; when doing so for GitHub, the `github-forge-production` user must have read access to the repository. For GitLab, the `galvanize-learn-production` user must have read access to the project. + +## Push to the Remote + +In the version control system of your choice, create a repository/project ([GitHub](https://docs.github.com/en/migrations/importing-source-code/using-the-command-line-to-import-source-code/adding-locally-hosted-code-to-github), [GitLab](https://docs.gitlab.com/ee/user/project/)), then commit all contents of the walkthrough: +``` +git add -A +git commit -m "testing learn publish" +git push origin main +``` + +## Publish the curriculum + +From within the project simply run +``` +learn publish +``` +from the command line. + +The `learn` CLI tool will ensure that an `autoconfig.yaml` file exists (unless a `config.yaml` is found) in a commit on the remote, then it will publish the curriculum contents. + +Any errors encountered while attempting to parse the directory will be provided in the event that the publish fails. + +The block will now be discoverable by users with proper access from the [searchable blocks index page](https://learn-2.galvanize.com/blocks). + +## Whats going on with all these UIDs? + +A lot of first time curriculum developers wonder why we have to define so many identifiers within the content, "Shouldn't the database handle this?" they ask. Well, because git repositories back the content rendered in Learn, there needs to be a way for Learn to keep track of the same content _across releases_. + +Suppose a student does work on one released commit of content, then a minor update to the curriculum is prepared and a second release is made for the block. If the lesson the student worked on did not fundamentally change, they still deserve credit for the work done on the prior release. + +Content files, units, and as you'll see challenges all require their own identifiers to keep track of the same content across releases. diff --git a/app/cmd/embeds/walkthrough/01-example-unit/03-markdown-examples.md b/app/cmd/embeds/walkthrough/01-example-unit/03-markdown-examples.md new file mode 100644 index 0000000..45968cc --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/03-markdown-examples.md @@ -0,0 +1,312 @@ +--- +Type: Lesson +UID: markdown-examples +--- + +# Markdown Examples + +Lessons are written in markdown. You can see a number of examples of markdown syntax in this file. + +You can view a complete list of available Learn custom markdown elements by running `learn md` and looking under the 'Other Markdown' section. + +File headers can be written to define attributes for the content file itself, which are under the 'Files' section. + +You can use a bare minimum template with the `-m` flag. + +## Link to other content in Learn + +Links to other markdown files in the repository will navigate within Learn. Write them with a relative path in the repo. For example: + +[This is a link to the Challenge Examples file in this repository `04-challenges.md`.](04-challenges.md) + +Links to lessons in other repos are possible by using permalinks. Once a block of curriculum is [published](02-publishing.md) and available on a cohort, each content file will have a chain link icon at the top available to instructors and administrators. + +Clicking this link will reveal the option to 'Copy page permalink' to your clipboard. Here is an example permalink you can copy: + +``` +https://learn-2.galvanize.com/content_link/github.com/gSchool/learn-content/other-challenge-attributes.md +``` + +## Link (external) + +Links to external content should be absolute links, starting with `http://` or `https://` + +[Google](https://www.google.com/) + +[Curriculum on github/gSchool](https://github.com/gSchool) + +*The markdown examples here are not necessary to read to continue the walkthrough. Read them for reference and to see what's possible with Learn markdown. + +## Callouts + +Callouts are Learn rendered sections of content to highlight + +### !callout-info +This information is the most important thing to read on the page! +### !end-callout + +### !callout-warning +Warnings don't really mean much when you know Danger is still an option. +### !end-callout + +### !callout-danger +You should probably do what this says. +### !end-callout + +### !callout-success +Yay? +### !end-callout + +### !callout-secondary +When grayscale is your style. +### !end-callout + +### !callout-star +Purple for when you want things to pop! +### !end-callout + +# H1 Top-Level Heading + +Galvanize is committed to creating opportunities for Veterans to gain the skills and knowledge they need to enter the tech industry after service to their country. As Veterans Day approaches, we’ll be chronicling the stories… + +## H2 Next-Level Heading + +At Galvanize, we’re putting a whole new spin on Study Hall with monthly sessions. At every Study Hall, industry all-stars present on one of three topics –– growth, funding, or product –– and collaborate… + +### H3 Next-Level Heading + +Just before Christmas last year, 41-year-old Chad Latham received a call from his lawyer. He had news from the President of the United States. At the time, Latham was in a 500-square-foot circle in a… + +#### H4 Next-Level Heading + +Kendra Lyndon wasn’t always interested in a career in web development. She spent years studying classical piano and earned her bachelor’s degree in music before taking on a role as an office assistant for a retail… + +##### H5 Next-Level Heading + +So you’ve gotten to know what personal branding is, you've developed a brand profile based on your strengths, and figured out how to customize your resume for each job without losing your uniqueness. What to do… + +###### H6 Next-Level Heading + +Before he joined the Galvanize Web Development Immersive Program, former US Army Sgt. Allen Fordham traveled the world in search of his passion. Growing up, Allen’s family moved a lot; he had lived in six… + +## Emphasis + +Words can have *emphasis*, **strong emphasis**, or ~~strikethrough~~. + +## Lists + +Numbered + +1. first +1. second +1. third + +Bulleted with `*` + +* one +* two +* three + +Bulleted with `-` + +- one +- two +- three + +## Images + +Images included in your repo will be automatically uploaded to S3 for display on Learn. + +The following image is placed inline ![react](images/react.png). + +The same image is on it's own line. + +![react](images/react.png) + +Large images will be scaled to fit the content column. + +![datascience](images/kmeans.png) + +## Images links
+ +This logo is a clickable link + +[![](images/github.jpg)](https://www.github.com) + +## Video embedded with a markdown tag + +### !vimeo +* id: 237762731 +### !end-vimeo + +## Video embedded with an iframe + + + +## Tables + +Here is a table with a header row + +| Tables | Are | Cool | +| ------------- |---------------| ------| +| enterprise | dsi | wdi | + +## Blockquotes + +> ## Look a heading in a blockquote! +> This is a very long line that will still be quoted properly when it wraps. Oh boy let's keep writing to make sure this is long enough to actually wrap for everyone. + + +## Rendering LaTeX for Math equations + +Block-style LaTeX supported. + +$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$ + +Inline LaTeX \( z^2 = x^2 + y^2 \) is also supported, but the delimiters are `\( and \)` to avoid conflicts over the use of single `$`. + +## Syntax Highlighting + +Inline `code` has single back-ticks around it. + +Code blocks are surrounded by have triple back-ticks, including the language for the correct syntax highlighting. + +```java +/** java example from https://highlightjs.org/static/demo/ **/ + +/** + * @author John Smith +*/ +package l2f.gameserver.model; + +public abstract class L2Char extends L2Object { + public static final Short ERROR = 0x0001; + + public void moveTo(int x, int y, int z) { + _ai = null; + log("Should not be called"); + if (1 > 5) { // wtf!? + return; + } + } +} +``` + +```js +// JS example from https://highlightjs.org/static/demo/ + +function $initHighlight(block, cls) { + try { + if (cls.search(/\bno\-highlight\b/) != -1) + return process(block, true, 0x0F) + + ` class="${cls}"`; + } catch (e) { + /* handle exception */ + } + for (var i = 0 / 2; i < classes.length; i++) { + if (checkCondition(classes[i]) === undefined) + console.log('undefined'); + } +} + +export $initHighlight; +``` + +```python +# Python example from https://highlightjs.org/static/demo/ + +@requires_authorization +def somefunc(param1='', param2=0): + r'''A docstring''' + if param1 > param2: # interesting + print 'Gre\'ater' + return (param2 - param1 + 1 + 0b10l) or None + +class SomeClass: + pass + +>>> message = '''interpreter +... prompt''' +``` + +```CSS +/* CSS example from https://highlightjs.org/static/demo/ */ + +@font-face { + font-family: Chunkfive; src: url('Chunkfive.otf'); +} + +body, .usertext { + color: #F0F0F0; background: #600; + font-family: Chunkfive, sans; +} + +@import url(print.css); +@media print { + a[href^=http]::after { + content: attr(href) + } +} +``` + +```html + + + +Title + + + + + + +

Title

+ + + +``` + +```jsx +// React example from https://learn-2.galvanize.com/cohorts/625/blocks/6/content_files/components/events-and-state.md + +class Echo extends React.Component { + + constructor(props) { + super(props) + this.state = { greeting: props.original } + } + + inputWasChanged = (e) => { + this.setState({greeting: e.target.value}) + } + + render() { + return ( +
+

+ +

+ { this.state.greeting } +
+ ) + } + +} +``` + +``` +Just text + +For data point in training set: + calculate distance from data point to new_value +Order distances in increasing order and take the first k +Make the prediction + +No language indicated, so no syntax highlighting. +But let's throw in a tag. +``` diff --git a/app/cmd/embeds/walkthrough/01-example-unit/04-challenges.md b/app/cmd/embeds/walkthrough/01-example-unit/04-challenges.md new file mode 100644 index 0000000..e4674a4 --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/04-challenges.md @@ -0,0 +1,705 @@ +--- +Type: Lesson +UID: challenges +--- + +# Challenge Examples + +Interactive questions called "challenges" can be added to any markdown lesson to check for understanding. These same challenges can also be used to construct practice assignments, quizzes, and assessments. + +You can view a complete list of available challenge types by running `learn md` and looking under the 'Questions' section. + +You can use a bare minimum template with the `-m` flag. + +## Structure + +You can see the basic structure of a multiple choice question by running: +``` +learn md mc -om +``` + +Each challenge begins with a `### !challenge` delimiter, and ends with `### !end-challenge` delimiter. Short one-line challenge attributes are defined in the challenge header, such as the `type`, `id`, `title`, or some type specific attributes such as `language` for code snippets. + +Other attributes are multiline, and are given their own delimiters. For example the `multiple-choice` type challenge requires a section to configure the available options; the delimiter for that section is `##### !options` and `##### !end-options`. + +When generating challenges with the `learn md` command, you can see explanations in comments for challenge attributes specific to that challenge. If you wish to omit these comments for a minimal template, pass the `-m` flag when generating the challenge. + +## Examples of Types + +* multiple choice (select one) +* checkbox (select multiple) +* short answer +* number +* paragraph +* code snippet--js, py, java, sql (code directly in Learn) +* custom-snippet--write your own `Dockerfile` and `test.sh` to allow student code to run in a customized container +* project, testable project (code locally, submit a repo) + +*Don't feel the need to correctly answer all the challenges below to complete the walkthrough, they are here for reference and to see how they render in Learn.* + +## Multiple Choice + +Multiple Choice challenges allow a student to submit a single answer to a multiple-choice question. + + + +### !challenge + + + + + +* type: multiple-choice +* id: 4fb73ef6-1492-45c9-b937-fe718cb80fea +* title: Example Multiple Choice Challenge + + + +### !question + +In which of these U.S. cities could you travel directly North, South, East, or West until you left the state, and arrive in the same new state no matter which direction you chose? + +### !end-question + + + +### !options + +a| Wheeling, West Virginia +b| Dover, Delaware +c| Stamford, Connecticut +d| Jacksonville, Florida + +### !end-options + + + +### !answer + +c| + +### !end-answer + + + +### !explanation + +If you headed in any of the four directions you would still end up in New York, with East being the most surprising as you'd first pass over ocean until you ended up in Long Island. + +### !end-explanation + +### !end-challenge + + + + + + +## Checkbox + +Checkbox challenges allow a student to submit multiple answers to a multiple-choice question. + + + +### !challenge + +* type: checkbox +* id: a2b0dd37-4d72-490f-ba26-c6e7b08d21a0 +* title: Example Checkbox Challenge + +##### !question + +Mark all of the ingredients in a peanut butter and jelly sandwich. + +##### !end-question + +##### !options + +* Peanut Butter +* Coleslaw +* Jelly +* Bread + +##### !end-options + +##### !answer + +* Peanut Butter +* Jelly +* Bread + +##### !end-answer + +### !end-challenge + + + + + +## Short Answer + +Short-answer challenges allow a student to submit a short answer, usually a single word, as the answer to a question. By default, the answer is evaluated as a case-insensitive exact match, but can also be evaluated as a regex. + +### !challenge + + + + + +* type: short-answer +* id: 1a3cc34f-ea21-4533-bed4-6da3c8c95a4e +* title: Example Short Answer Challenge + + + +### !question + +What will the following code produce? + +```javascript +var myArray = ["Elie", "Janey", "Matt", "Parker", "Tim"]; +myArray[3] +``` + +### !end-question + + + +#### !placeholder + +What does myArray[3] equal? + +#### !end-placeholder + + + +### !answer +"Parker" +### !end-answer + +### !end-challenge + + + + + +## Number + +Number challenges allow a student to submit a number as the answer to a question. The answer is evaluated numerically, and the student can answer with a decimal or a fraction--so that things like 3/10, 30/100, .3, 0.3, 0.300 etc. are all equivalent. There also also an option when creating the challenge to define the precision used when the answer is scored -- see the code below for details. + + + +### !challenge + + + + + + +* type: number +* id: e88f0c35-7f2d-4990-81c1-a529d5e81dbb +* title: Example Number Challenge +* decimal: 5 + + + +### !question +Suppose a card is drawn from a standard 52 card deck. What's the probability that the card is a queen? +### !end-question + + + +#### !placeholder +Write your answer as a decimal to 5 places +#### !end-placeholder + + + +### !answer +1/13 +### !end-answer + +### !end-challenge + + + + + +## Paragraph + +Paragraph Challenges allow a student to submit a long free-form text answer to a question, such as a definition of explanation. The answers to these Challenges are not evaluated by Learn, but are available for the instructor to view. + + + +### !challenge + + + + + +* type: paragraph +* id: f397a35a-2d2a-42e2-a8aa-9bc4be353e59 +* title: Example Paragraph Challenge + + + +### !question +Explain at least 2 benefits of writing semantic HTML. +### !end-question + + + +#### !placeholder +Write your answer here +#### !end-placeholder + + + +### !explanation +Your answer may have covered accessibility, SEO, and human readability. +### !end-explanation + +### !end-challenge + + + + +## Javascript Code Snippet + +Code Snippet Challenges allow a student to write code directly in Learn. The submission is evaluated against unit tests that are setup as part of the Challenge. The student then sees the standard output from the test runner in Learn. + +Attributes like tests can be written to external files with the attribute `test_file`, allowing for ease of local testing. + + + +### !challenge + + + + + + + + +* type: code-snippet +* id: dd9c31af-0fe8-440d-b4ec-bab3e8dc8a1d +* language: javascript18 +* title: Javascript `Repeats` Function + + + +### !question + +## Repeats + +Write a function named `repeats` +* `repeats` should take one argument, `str`, the string to test. +* For this exercise, you can assume that `str` is a string. +* If the first half of `str` equals the second half, return true. +* If `str` is an empty string, return true. +* Otherwise, return false. +* Do not use the `.repeat` method. + +### !end-question + + + +#### !placeholder + +```js +function repeats(str) { + // return str.substring(0, str.length/2) === str.substring(str.length/2, str.length); +} +``` + +#### !end-placeholder + + + +### !tests + +```js +describe('repeats', function() { + + it("should return true when given an empty string (which seems strange, but go with it :) )", function() { + expect(repeats(""), "Default value is incorrect").to.deep.eq(true) + }) + + it("should return true when the second half of the string equals the first", function() { + expect(repeats("bahbah")).to.deep.eq(true) + expect(repeats("nananananananana")).to.deep.eq(true) + }) + + it("should return false when the second half of the string does not equal the first", function() { + expect(repeats("bahba")).to.deep.eq(false) + expect(repeats("nananananann")).to.deep.eq(false) + }) + + it("should not use .repeat", function() { + expect(repeats.toString()).to.not.match(/\.repeat/) + }) + +}) +``` +### !end-tests + +### !end-challenge + + + + + +## Python Code Snippet + +Code Snippet Challenges allow a student to write Python directly in Learn. The submission is evaluated against unit tests that are setup as part of the Challenge. The student then sees the standard output from the test runner in Learn. + + + +### !challenge + + + + + + +* type: code-snippet +* language: python3.9 +* id: 6f1a61d2-a3b4-402d-83be-38d443f03e72 +* title: filter by class + + + +### !question + +Implement the function `filter_by_class`: It takes a feature matrix, `X`, an array of classes, `y`, and a class label, `label`. It should return all of the rows from X whose label is the given label. + +```python +>>> X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) +>>> y = np.array(["a", "c", "a", "b"]) +>>> filter_by_class(X, y, "a") +array([[1, 2, 3], + [7, 8, 9]]) +>>> filter_by_class(X, y, "b") +array([[10, 11, 12]]) +``` +### !end-question + + + +### !placeholder + +```python +def filter_by_class(X, y, label): + ''' + INPUT: 2 dimensional numpy array, numpy array, object + OUTPUT: 2 dimensional numpy array + + Return the rows from X whose corresponding label from y is the given label. + ''' + # return X[y == label] +``` +### !end-placeholder + + + +### !tests +```python +import unittest +import main as p +import numpy as np + +class TestChallenge(unittest.TestCase): + def test_filter_by_class1(self): + X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) + y = np.array(["a", "c", "a", "b"]) + result = p.filter_by_class(X, y, "a") + answer = np.array([[1, 2, 3], [7, 8, 9]]) + assert np.array_equal(result, answer) + + def test_filter_by_class2(self): + X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) + y = np.array(["a", "c", "a", "b"]) + result = p.filter_by_class(X, y, "b") + answer = np.array([[10, 11, 12]]) + assert np.array_equal(result, answer) +``` +### !end-tests + +### !end-challenge + + + + + +## Java Code Snippet + +Code Snippet Challenges allow a student to write Java directly in Learn. The submission is evaluated against unit tests that are setup as part of the Challenge. The student then sees the standard output from the test runner in Learn. + + + +### !challenge + +* type: code-snippet +* language: java +* id: 48900333-21b1-47e8-bb04-9666cf3b4a03 +* title: Single comparison + +### !question + +In the space given below, define and implement a method called `isActive`. It takes as input a `String` and returns `true` if the passed in string is "active", `false` if it is any other string. + +### !end-question + +### !setup + +// [to allow student to submit simple statements, wrap the submission +// using the !setup and !tests sections; example below] +class ChallengeSolution { + +### !end-setup + +### !placeholder +boolean isActive(String status) { + // Implement your solution +} +### !end-placeholder + +### !tests + +} + +public class SnippetTest { + + ChallengeSolution solution = new ChallengeSolution(); + + @Test + public void emptyStringReturnsFalse() { + String input = new String(""); + assertEquals(false, solution.isActive(input), "For empty string"); + } + + @Test + public void singleLetterReturnsFalse() { + String input = new String("a"); + assertEquals(false, solution.isActive(input), "For single letter string"); + } + + @Test + public void activeReturnsTrue() { + String input = new String("active"); + assertEquals(true, solution.isActive(input), "For new \"active\" string"); + } + + @Test + public void substringActiveReturnsFalse() { + String input = new String("ctive"); + assertEquals(false, solution.isActive(input), "For substrings of \"active\""); + } + + @Test + public void activeSubstringReturnsFalse() { + String input = new String("superactive"); + assertEquals(false, solution.isActive(input), "For input where a substring is \"active\""); + } +} +### !end-tests + +### !end-challenge + + + + +## SQL Code Snippet + +SQL Snippet Challenges allow a student to write SQL `SELECT` queries against a database defined by a curriculum developer. The submission is evaluated against a supplied test query. The student sees a truncated set of rows as if their query was run from the `psql` interpreter, and the challenge is graded against row and column matches, along with data matches. `ORDER BY` clauses will be respected if they are supplied in the test query. + +The database used is: + +`PostgreSQL 14.7 on x86_64-pc-linux-gnu` + + + +### !challenge + + + + + + + +* type: code-snippet +* language: sql +* id: 7264b4e8-1a0d-44c5-b019-601305617ff8 +* title: Absence of a join with Left Outer Join +* data_path: /01-example-unit/sql-files/foodtruck.sql + + + +##### !question + +Given a `users` table with a primary key of `id` and a `trucks` table with a foreign key that references the `users.id` column with `trucks.owner_id`, select all user information from users who do not own trucks, ordered by their last name descending, `users.last`. + +##### !end-question + + + +##### !placeholder + +```sql +-- Write your query to select users who do not own trucks +select users.* from users +left outer join trucks on users.id = trucks.owner_id +where trucks.owner_id IS NULL +order by users.last desc +``` + +##### !end-placeholder + + + +##### !tests + +SELECT users.* +FROM users + LEFT OUTER JOIN trucks + ON trucks.owner_id = users.id +WHERE owner_id IS NULL +ORDER BY users.last DESC + +##### !end-tests + +### !end-challenge + + + + +## Custom Snippet Challenge + +The custom snippet challenge allows students to submit the input as a file to run inside customizable a container. The `docker_directory_path` attribute should always be from the root of the project and be a directory containing a `Dockerfile` and `test.sh` file. + +### Steps Learn Takes + +1. The image will build +1. The container will start +1. The text editor input is copied to `submission.txt` in the `WORKDIR` +1. The container runs `bash test.sh` and the output captured +1. The answer is correct only if the exit code is 0 + + + + +### !challenge + +* type: custom-snippet +* language: text +* id: aa5958ba-9d7a-4751-8d2d-38d4f5769f0d +* title: hello world +* docker_directory_path: /01-example-unit/custom-snippets/hello-world + + + +##### !question + +Write the words "Hello world!" in the editor below. Then inspect the contents of the docker directory path in the walkthrough `/01-example-unit/custom-snippets/hello-world/Dockerfile` to learn more. + +` + +##### !end-question + +##### !placeholder + +##### !end-placeholder + + + + + + +### !end-challenge + + + +## Project Challenge + +Project Challenges allow a student to do work outside of Learn. After completing the work, the student submits a link (typically from Github) to the work that they did for tracking and review within Learn. + + + +### !challenge + + + + + +* type: project +* id: 372d5f1f-e432-47f1-8de6-d0643f3773dc +* title: JS Native Array Methods + + + +##### !question + +### JS Native Array Methods + +Submit the github repo containing your work on the js-native-array-methods [repository](https://github.com/gSchool/js-native-array-methods). + +##### !end-question + + + +##### !placeholder + +https://github.com//js-native-array-methods + +##### !end-placeholder + +### !end-challenge + + + + + +## Testable Project + +Just like Project Challenges, but Learn will automatically run tests included in the repo and make the results available to the instructor. + +To do this, you need two things -- + +1. An exercise repo that is setup to run in Docker (covered [here](https://learn-2.galvanize.com/cohorts/667/blocks/13/content_files/Testing-Project-Challenges.md)). +2. A project challenge where the students can submit their exercise repo. + + + + + +### !challenge + +* type: testable-project +* id: a06bbaaf-b851-456b-b928-520883bcfd1b +* title: A simple upstream example +* upstream: https://github.com/gSchool/simple-upstream +* validate_fork: false + + + +##### !question + +A simple example which runs a single test file. Comments in the upstream files explain more details; you can fork https://github.com/gSchool/simple-upstream to try it out. Student submissions do not have to be forked from the upstream, and starter code can be distributed however you see fit. + +##### !end-question + +##### !placeholder + +https://github.com//simple-upstream + +##### !end-placeholder + + + + + + +### !end-challenge + + diff --git a/app/cmd/embeds/walkthrough/01-example-unit/05-checkpoint.md b/app/cmd/embeds/walkthrough/01-example-unit/05-checkpoint.md new file mode 100644 index 0000000..b47a290 --- /dev/null +++ b/app/cmd/embeds/walkthrough/01-example-unit/05-checkpoint.md @@ -0,0 +1,205 @@ +--- +# autoconfig.yml will use these settings. config.yml will override. +Type: Checkpoint +UID: 2df27a2d-6db3-4dd6-aa82-2e6169e5b77f +# DefaultVisibility: hidden # Uncomment this line to default Checkpoint to hidden +MaxCheckpointSubmissions: 1 +# EmailOnCompletion: true # Uncomment this line to send instructors an email once a student has completed a checkpoint +TimeLimit: 60 +# Autoscore: true # Uncomment this line to finalize checkpoint scores without instructor review +--- + +# Checkpoint Example + +Each unit can have only one Checkpoint, and the checkpoint must have challenges. Checkpoints can be configured to score points automatically, grant a limited number of attempts, require a certain time limit to complete, and email the instructors upon completion. + +See the header on this file `01-example-unit/05-checkpoint.md` to configure these options. + +Saving and Exiting will not pause the timer, but will allow you to return to the test if you wish. + +If a time limit is set, the checkpoint will be graded if the time elapses without submitting, even if you close the browser. + + + +### !challenge + +* type: multiple-choice +* id: 06f68dd8-0819-4504-8d53-96246dc2d83f +* title: How did it go? +* points: 3 + + + + +##### !question + +1. How well do you know the material from this lesson? Check the answer in the markdown; this is how you make all options valid in a multiple choice challenge. + +##### !end-question + +##### !options + +* I got it! +* More practice please! +* I need some help! + +##### !end-options + +##### !answer + +* + +##### !end-answer + +### !end-challenge + + + + + +### !challenge + +* type: checkbox +* id: b73598d5-4c11-4900-a711-cc30a9d57f21 +* title: JSX components +* points: 10 + + + + +##### !question + +Which yaml files can be used when configuring your repository contents for a block? + +##### !end-question + +##### !options + +* `description.yaml` +* `course.yaml` +* `manifest.yaml` +* `config.yaml` +* `yak.yaml` +* `autoconfig.yaml` + +##### !end-options + +##### !answer + +* `description.yaml` +* `config.yaml` +* `autoconfig.yaml` + +##### !end-answer + +### !end-challenge + + + + + +### !challenge + +* type: short-answer +* id: bc7be392-0529-4846-a7c7-09c356297fea +* title: Iterating + + + + +##### !question + +Which `learn` CLI command lets you view content in Learn to iterate quickly before publishing? + +Check this short answer to see how regex is used to match answers. You can use [Rubular](https://rubular.com/) to quickly test your own regular expressions. + +##### !end-question + +##### !placeholder +your answer +##### !end-placeholder + +##### !answer + +/(preview|learn preview)/ + +##### !end-answer + +### !end-challenge + + + +### !challenge + +* type: checkbox +* id: fb4e6a97-ee62-4ffa-80a6-860f1654353c +* title: Explanations when incorrect +* points: 3 + + +##### !question + +Which of the following are Learn callout colors? Try and get the answer wrong, see how you are guided to the correct answer, then check the markdown to see how explanations are used to create this interactive challenge. + +The `!explanation` can be configured with different variants to supply custom responses to checkbox and multiple-choice challenges. The options are: + +* `!explanation-correct` -> The response when the answer is correct. +* `!explanation-incorrect` -> The default incorrect response if no other matches are found. +* `!explanation: