chore(seed): bring in curriculum repo into the main repo

This commit is contained in:
Mrugesh Mohapatra
2018-09-27 12:38:05 +05:30
402 changed files with 176249 additions and 0 deletions

8
curriculum/.babelrc Normal file
View File

@ -0,0 +1,8 @@
{
"presets": [ "env", "react", "stage-0" ],
"plugins": [
"transform-runtime",
"babel-plugin-add-module-exports",
"lodash"
]
}

12
curriculum/.editorconfig Normal file
View File

@ -0,0 +1,12 @@
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

2
curriculum/.eslintignore Normal file
View File

@ -0,0 +1,2 @@
node_modules
.webpack

3
curriculum/.eslintrc Normal file
View File

@ -0,0 +1,3 @@
{
"extends": "freecodecamp"
}

74
curriculum/.github/CODE_OF_CONDUCT.md vendored Normal file
View File

@ -0,0 +1,74 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at team@freecodecamp.org. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@ -0,0 +1,29 @@
---
name: Bug report
about: Report an issue or a bug after you have searched through existing issues
---
#### Describe the bug
A clear and concise description of what the bug is.
#### To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
#### Expected behavior
A clear and concise description of what you expected to happen.
#### Screenshots
If applicable, add screenshots to help explain your problem.
#### Desktop (please complete the following information):
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
#### Additional context
Add any other context about the problem here.

View File

@ -0,0 +1,17 @@
---
name: Feature request
about: Suggest a challenge or a feature for this project
---
#### Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
#### Describe the solution you'd like
A clear and concise description of what you want to happen.
#### Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
#### Additional context
Add any other context or screenshots about the feature request here.

View File

@ -0,0 +1,31 @@
#### Description
<!-- Describe your changes in detail below this line-->
<!--
Before creating a PR, please make sure to verify the following by marking the checkboxes below as complete
- [x] Like this!
or optionally you can click the checkboxes after you have opened the pull request.
-->
#### Pre-Submission Checklist
- [ ] Your pull request targets the `dev` branch.
- [ ] Branch starts with either `fix/`, `feature/`, or `translate/` (e.g. `fix/challenge-tests`)
- [ ] All new and existing tests pass the command `npm test`.
- [ ] Use `npm run commit` to generate a conventional commit message.
Learn more here: <https://conventionalcommits.org/#why-use-conventional-commits>
- [ ] The changes were done locally on your machine and NOT GitHub web interface.
If they were done on the web interface you have ensured that you are creating conventional commit messages.
#### Checklist:
- [ ] Tested changes locally.
- [ ] Addressed currently open issue (replace XXXXX with an issue no in next line)
Closes #XXXXX

74
curriculum/.gitignore vendored Normal file
View File

@ -0,0 +1,74 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Compiled distribution folder
dist/
# Dependency directories
node_modules/
jspm_packages/
# Unpacked challenge files
unpacked/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
# IDE
.idea
*.iml
.DS_Store
Thumbs.db
.vscode/

3
curriculum/.npmignore Normal file
View File

@ -0,0 +1,3 @@
*
!dist/*.js
!dist/challenges/**/*.json

5
curriculum/.prettierrc Normal file
View File

@ -0,0 +1,5 @@
{
"semi": true,
"singleQuote": true,
"trailingComma": "none"
}

31
curriculum/.travis.yml Normal file
View File

@ -0,0 +1,31 @@
language: node_js
node_js:
- 'lts/*'
cache:
directories:
- ~/.npm
- node_modules
notifications:
email:
on_success: change
on_failure: always
script:
- commitlint-travis
- npm run lint
- npm run test
deploy:
provider: script
skip_cleanup: true
script:
- npx semantic-release
branches:
except:
- /^v\d+\.\d+\.\d+$/
sudo: false

221
curriculum/CHANGELOG.md Normal file
View File

@ -0,0 +1,221 @@
## [3.2.1](https://github.com/freeCodeCamp/curriculum/compare/v3.2.0...v3.2.1) (2018-09-25)
### Bug Fixes
* Add videoUrl field ([#298](https://github.com/freeCodeCamp/curriculum/issues/298)) ([ce3cc22](https://github.com/freeCodeCamp/curriculum/commit/ce3cc22))
# [3.2.0](https://github.com/freeCodeCamp/curriculum/compare/v3.1.2...v3.2.0) (2018-09-20)
### Bug Fixes
* **challenges:** a sentence didn't make sense, so I modified it ([3d77920](https://github.com/freeCodeCamp/curriculum/commit/3d77920)), closes [#18046](https://github.com/freeCodeCamp/curriculum/issues/18046)
* **challenges:** add missing test to check for for css class ([6e42f53](https://github.com/freeCodeCamp/curriculum/commit/6e42f53)), closes [#254](https://github.com/freeCodeCamp/curriculum/issues/254)
* **challenges:** add note at bottom of description in d3 challenge ([c60d332](https://github.com/freeCodeCamp/curriculum/commit/c60d332)), closes [#17767](https://github.com/freeCodeCamp/curriculum/issues/17767)
* **challenges:** add solution, test to project euler problems ([f572324](https://github.com/freeCodeCamp/curriculum/commit/f572324))
* **challenges:** add solutions to first 3 debugging challenges ([c2e5794](https://github.com/freeCodeCamp/curriculum/commit/c2e5794))
* **challenges:** add test to check user is using \W in Regex ([296cf44](https://github.com/freeCodeCamp/curriculum/commit/296cf44))
* **challenges:** add test to lookahead regex challenge ([e044de4](https://github.com/freeCodeCamp/curriculum/commit/e044de4)), closes [#209](https://github.com/freeCodeCamp/curriculum/issues/209)
* **challenges:** added code tags ([065036b](https://github.com/freeCodeCamp/curriculum/commit/065036b)), closes [#18054](https://github.com/freeCodeCamp/curriculum/issues/18054)
* **challenges:** added solutions to project euler problems 28, 31 ([5e12499](https://github.com/freeCodeCamp/curriculum/commit/5e12499))
* **challenges:** adding code tags to description ([57d5b55](https://github.com/freeCodeCamp/curriculum/commit/57d5b55)), closes [#17911](https://github.com/freeCodeCamp/curriculum/issues/17911)
* **challenges:** adding negative integer to challenge to improve tests ([#211](https://github.com/freeCodeCamp/curriculum/issues/211)) ([2adc516](https://github.com/freeCodeCamp/curriculum/commit/2adc516))
* **challenges:** allow user to comment out undesired code ([72c2407](https://github.com/freeCodeCamp/curriculum/commit/72c2407))
* **challenges:** challenge description is formatted and concised ([dcd8e45](https://github.com/freeCodeCamp/curriculum/commit/dcd8e45))
* **challenges:** change challengeType to fix help button ([ddcc661](https://github.com/freeCodeCamp/curriculum/commit/ddcc661))
* **challenges:** change definition of complementary colors ([#299](https://github.com/freeCodeCamp/curriculum/issues/299)) ([c022dff](https://github.com/freeCodeCamp/curriculum/commit/c022dff))
* **challenges:** check for shorthand character in regex ([#238](https://github.com/freeCodeCamp/curriculum/issues/238)) ([0bf8d32](https://github.com/freeCodeCamp/curriculum/commit/0bf8d32))
* **challenges:** commented output was wrong ([3cb972e](https://github.com/freeCodeCamp/curriculum/commit/3cb972e))
* **challenges:** converts delete html test to regex ([d80d98d](https://github.com/freeCodeCamp/curriculum/commit/d80d98d)), closes [#251](https://github.com/freeCodeCamp/curriculum/issues/251)
* **challenges:** corrected challenge instructions ([159203a](https://github.com/freeCodeCamp/curriculum/commit/159203a))
* **challenges:** fix [#17155](https://github.com/freeCodeCamp/curriculum/issues/17155) ([cb21e59](https://github.com/freeCodeCamp/curriculum/commit/cb21e59))
* **challenges:** fix confusing destructuring es6 challenge ([1a4f6a8](https://github.com/freeCodeCamp/curriculum/commit/1a4f6a8)), closes [#213](https://github.com/freeCodeCamp/curriculum/issues/213)
* **challenges:** fix description in css variable fallback challenge ([bc33a03](https://github.com/freeCodeCamp/curriculum/commit/bc33a03)), closes [freeCodeCamp/freeCodeCamp#17546](https://github.com/freeCodeCamp/freeCodeCamp/issues/17546)
* **challenges:** fix flex direction row regex ([25ea07e](https://github.com/freeCodeCamp/curriculum/commit/25ea07e)), closes [#260](https://github.com/freeCodeCamp/curriculum/issues/260)
* **challenges:** fix grammar and spelling errors ([#244](https://github.com/freeCodeCamp/curriculum/issues/244)) ([b0c0b74](https://github.com/freeCodeCamp/curriculum/commit/b0c0b74))
* **challenges:** fix grid-gap shorthand regex ([#232](https://github.com/freeCodeCamp/curriculum/issues/232)) ([a49f45e](https://github.com/freeCodeCamp/curriculum/commit/a49f45e)), closes [#229](https://github.com/freeCodeCamp/curriculum/issues/229)
* **challenges:** fix grid-gap shorthand regex ([#237](https://github.com/freeCodeCamp/curriculum/issues/237)) ([b369fa0](https://github.com/freeCodeCamp/curriculum/commit/b369fa0)), closes [#229](https://github.com/freeCodeCamp/curriculum/issues/229)
* **challenges:** fix regex in a JS challenge ([#257](https://github.com/freeCodeCamp/curriculum/issues/257)) ([6058da3](https://github.com/freeCodeCamp/curriculum/commit/6058da3))
* **challenges:** fix typo in wrap-reverse description ([434ea5c](https://github.com/freeCodeCamp/curriculum/commit/434ea5c))
* **challenges:** fixed challenge accepted without any new code ([96b39c1](https://github.com/freeCodeCamp/curriculum/commit/96b39c1)), closes [#198](https://github.com/freeCodeCamp/curriculum/issues/198)
* **challenges:** fixed esc chars in managing packages with npm lesson ([6335a15](https://github.com/freeCodeCamp/curriculum/commit/6335a15))
* **challenges:** fixed tests to check for pre operators ([ded4705](https://github.com/freeCodeCamp/curriculum/commit/ded4705)), closes [#199](https://github.com/freeCodeCamp/curriculum/issues/199)
* **challenges:** fixed typo in algorithms and ds ([31957a4](https://github.com/freeCodeCamp/curriculum/commit/31957a4))
* **challenges:** Incorrect html closing tag ([a1464f0](https://github.com/freeCodeCamp/curriculum/commit/a1464f0))
* **challenges:** insufficient objectives for javascript_algorithm/es6/19 ([7707b18](https://github.com/freeCodeCamp/curriculum/commit/7707b18))
* **challenges:** missing space in code example ([c50cc4e](https://github.com/freeCodeCamp/curriculum/commit/c50cc4e))
* **challenges:** remove race condition from react lifecycle challenge ([a20ac56](https://github.com/freeCodeCamp/curriculum/commit/a20ac56))
* **challenges:** removed duplicate css top property ([0a79c58](https://github.com/freeCodeCamp/curriculum/commit/0a79c58))
* **challenges:** rephrased wording in applied visual design ([#268](https://github.com/freeCodeCamp/curriculum/issues/268)) ([d560d58](https://github.com/freeCodeCamp/curriculum/commit/d560d58))
* **challenges:** replaced em tags with code tags ([68daaf7](https://github.com/freeCodeCamp/curriculum/commit/68daaf7)), closes [#18048](https://github.com/freeCodeCamp/curriculum/issues/18048)
* **challenges:** reword test text and improve test accuracy ([f834a98](https://github.com/freeCodeCamp/curriculum/commit/f834a98))
* **challenges:** small edit to correct sematic issues ([322bf80](https://github.com/freeCodeCamp/curriculum/commit/322bf80))
* clickjacking challenge description ([037990c](https://github.com/freeCodeCamp/curriculum/commit/037990c))
* **challenges:** spelling and grammar errors addressed ([8f17adf](https://github.com/freeCodeCamp/curriculum/commit/8f17adf))
* **challenges:** typo ([4f7faba](https://github.com/freeCodeCamp/curriculum/commit/4f7faba))
* **challenges:** update test and add solution for DS challenge ([d1b2075](https://github.com/freeCodeCamp/curriculum/commit/d1b2075)), closes [#164](https://github.com/freeCodeCamp/curriculum/issues/164)
* **challenges:** Update test to include whitespace ([#272](https://github.com/freeCodeCamp/curriculum/issues/272)) ([77689f4](https://github.com/freeCodeCamp/curriculum/commit/77689f4)), closes [#271](https://github.com/freeCodeCamp/curriculum/issues/271)
* **schema:** change schema and unpack script ([b014b23](https://github.com/freeCodeCamp/curriculum/commit/b014b23))
### Features
* **challenges:** add browser fallback challenge ([b090e8b](https://github.com/freeCodeCamp/curriculum/commit/b090e8b)), closes [freeCodeCamp/freeCodeCamp#17546](https://github.com/freeCodeCamp/freeCodeCamp/issues/17546)
## [3.1.2](https://github.com/freeCodeCamp/curriculum/compare/v3.1.1...v3.1.2) (2018-07-31)
### Bug Fixes
* **challenges:** allow for omitted unit after zero values ([45b573b](https://github.com/freeCodeCamp/curriculum/commit/45b573b)), closes [#166](https://github.com/freeCodeCamp/curriculum/issues/166)
* **challenges:** changed complementary color for blue to orange ([e41f078](https://github.com/freeCodeCamp/curriculum/commit/e41f078)), closes [#17934](https://github.com/freeCodeCamp/curriculum/issues/17934)
* **challenges:** fix test in hr challenge ([#189](https://github.com/freeCodeCamp/curriculum/issues/189)) ([2edb306](https://github.com/freeCodeCamp/curriculum/commit/2edb306))
* **challenges:** fix third test for template literals ([b8d004e](https://github.com/freeCodeCamp/curriculum/commit/b8d004e)), closes [#135](https://github.com/freeCodeCamp/curriculum/issues/135)
* **challenges:** fixes escaping of ([fd8c9e4](https://github.com/freeCodeCamp/curriculum/commit/fd8c9e4))
* **scripts:** fix unpack and repack scripts for the new challenge schema ([52ed7cf](https://github.com/freeCodeCamp/curriculum/commit/52ed7cf))
## [3.1.1](https://github.com/freeCodeCamp/curriculum/compare/v3.1.0...v3.1.1) (2018-07-28)
### Bug Fixes
* **challenges:** improve test for mongodb and mongoose ([8ae372a](https://github.com/freeCodeCamp/curriculum/commit/8ae372a))
# [3.1.0](https://github.com/freeCodeCamp/curriculum/compare/v3.0.1...v3.1.0) (2018-07-27)
### Bug Fixes
* **challenge:** syntax error in sample code snippet ([1d3e076](https://github.com/freeCodeCamp/curriculum/commit/1d3e076))
* **challenge:** typos in first Basic CSS challenge test ([5e41e74](https://github.com/freeCodeCamp/curriculum/commit/5e41e74))
* **challenges:** add code input space for final d3 challenge ([f0b7ea9](https://github.com/freeCodeCamp/curriculum/commit/f0b7ea9))
* **challenges:** add comments to getter/setter instructions codeblock ([9e9bc27](https://github.com/freeCodeCamp/curriculum/commit/9e9bc27)), closes [#92](https://github.com/freeCodeCamp/curriculum/issues/92)
* **challenges:** add solution project euler 52 ([f31fe38](https://github.com/freeCodeCamp/curriculum/commit/f31fe38))
* **challenges:** add solution to project euler 53 ([56d7caf](https://github.com/freeCodeCamp/curriculum/commit/56d7caf))
* **challenges:** add user story to tribute page challange ([12c78d4](https://github.com/freeCodeCamp/curriculum/commit/12c78d4))
* **challenges:** allows single quotes ([57dab6d](https://github.com/freeCodeCamp/curriculum/commit/57dab6d))
* **challenges:** broken link ([64b93df](https://github.com/freeCodeCamp/curriculum/commit/64b93df))
* **challenges:** broken link ([de30ac8](https://github.com/freeCodeCamp/curriculum/commit/de30ac8)), closes [#17823](https://github.com/freeCodeCamp/curriculum/issues/17823)
* **challenges:** change del tag to s tag ([4dc7589](https://github.com/freeCodeCamp/curriculum/commit/4dc7589))
* **challenges:** change green-box class margin to match red-box ([9fd5533](https://github.com/freeCodeCamp/curriculum/commit/9fd5533)), closes [#169](https://github.com/freeCodeCamp/curriculum/issues/169)
* **challenges:** change innerHTML to textContent ([#160](https://github.com/freeCodeCamp/curriculum/issues/160)) ([06e1ba1](https://github.com/freeCodeCamp/curriculum/commit/06e1ba1)), closes [freeCodeCamp/freeCodeCamp#17888](https://github.com/freeCodeCamp/freeCodeCamp/issues/17888)
* **challenges:** fix 2nd test bug ([362fc8a](https://github.com/freeCodeCamp/curriculum/commit/362fc8a)), closes [#17769](https://github.com/freeCodeCamp/curriculum/issues/17769) [#17039](https://github.com/freeCodeCamp/curriculum/issues/17039) [#16967](https://github.com/freeCodeCamp/curriculum/issues/16967)
* **challenges:** fix broken tests - es6_declarative_function ([667dba9](https://github.com/freeCodeCamp/curriculum/commit/667dba9))
* **challenges:** fix challenge for fallback value of CSS variable ([3abf7ad](https://github.com/freeCodeCamp/curriculum/commit/3abf7ad))
* **challenges:** fix description and tests to use sync hashing ([cfa99ef](https://github.com/freeCodeCamp/curriculum/commit/cfa99ef)), closes [#119](https://github.com/freeCodeCamp/curriculum/issues/119)
* **challenges:** fix initial contents ([9329543](https://github.com/freeCodeCamp/curriculum/commit/9329543))
* **challenges:** fix regex (es6 : import vs require) ([f4d598f](https://github.com/freeCodeCamp/curriculum/commit/f4d598f)), closes [#108](https://github.com/freeCodeCamp/curriculum/issues/108)
* **challenges:** fix regex in applied visual design challenge ([#162](https://github.com/freeCodeCamp/curriculum/issues/162)) ([5a34767](https://github.com/freeCodeCamp/curriculum/commit/5a34767)), closes [#161](https://github.com/freeCodeCamp/curriculum/issues/161) [#161](https://github.com/freeCodeCamp/curriculum/issues/161)
* **challenges:** fix regex to allow redundant space characters ([8b99b8b](https://github.com/freeCodeCamp/curriculum/commit/8b99b8b))
* **challenges:** fix typo in "split string into array using split" ([5b27dfd](https://github.com/freeCodeCamp/curriculum/commit/5b27dfd))
* **challenges:** fix typo in a "mongodb and mongoose" challenge ([bd67a66](https://github.com/freeCodeCamp/curriculum/commit/bd67a66))
* **challenges:** fix typo in a node and express challenge ([78d86a4](https://github.com/freeCodeCamp/curriculum/commit/78d86a4))
* **challenges:** fix typo in findOneAndUpdate() challenge ([ab912e4](https://github.com/freeCodeCamp/curriculum/commit/ab912e4))
* **challenges:** fix typo in node and express challenge ([7f3ed42](https://github.com/freeCodeCamp/curriculum/commit/7f3ed42))
* **challenges:** fix typos ([82f85b0](https://github.com/freeCodeCamp/curriculum/commit/82f85b0))
* **challenges:** fixed a typo in Data structures challege ([a4f810e](https://github.com/freeCodeCamp/curriculum/commit/a4f810e)), closes [freeCodeCamp/freeCodeCamp#17786](https://github.com/freeCodeCamp/freeCodeCamp/issues/17786)
* **challenges:** fixed RegEx for template literals javascript challenge ([66d8463](https://github.com/freeCodeCamp/curriculum/commit/66d8463)), closes [#65](https://github.com/freeCodeCamp/curriculum/issues/65)
* **challenges:** fixed regex in a challenge ([c28aac0](https://github.com/freeCodeCamp/curriculum/commit/c28aac0)), closes [freeCodeCamp/freeCodeCamp#17861](https://github.com/freeCodeCamp/freeCodeCamp/issues/17861)
* **challenges:** glitch links in backend projects now open in new tabs ([507c22d](https://github.com/freeCodeCamp/curriculum/commit/507c22d)), closes [#17799](https://github.com/freeCodeCamp/curriculum/issues/17799)
* **challenges:** grammatical error ([5308332](https://github.com/freeCodeCamp/curriculum/commit/5308332))
* **challenges:** improve template literal challenge instructions ([99f4b9f](https://github.com/freeCodeCamp/curriculum/commit/99f4b9f))
* **challenges:** inline style semicolon consistency ([3557016](https://github.com/freeCodeCamp/curriculum/commit/3557016)), closes [#17909](https://github.com/freeCodeCamp/curriculum/issues/17909)
* **challenges:** minor css grid typo ([f147430](https://github.com/freeCodeCamp/curriculum/commit/f147430))
* **challenges:** moved the `<em>` tag inside the `<p>` tag ([128794d](https://github.com/freeCodeCamp/curriculum/commit/128794d))
* **challenges:** remove obsolete mention of beta and update link [#144](https://github.com/freeCodeCamp/curriculum/issues/144) ([59d98b8](https://github.com/freeCodeCamp/curriculum/commit/59d98b8))
* **challenges:** replace assertions in authentication with socket.io ([20e3617](https://github.com/freeCodeCamp/curriculum/commit/20e3617)), closes [#82](https://github.com/freeCodeCamp/curriculum/issues/82)
* **challenges:** typo and grammatical error ([c1160c5](https://github.com/freeCodeCamp/curriculum/commit/c1160c5))
* **challenges:** typo error ([2d3ca6d](https://github.com/freeCodeCamp/curriculum/commit/2d3ca6d))
* **challenges:** typo in javascript algorithms/debugging/2 ([8286ff9](https://github.com/freeCodeCamp/curriculum/commit/8286ff9))
* **challenges:** typos in some basic node and express challenges ([93277e5](https://github.com/freeCodeCamp/curriculum/commit/93277e5)), closes [#113](https://github.com/freeCodeCamp/curriculum/issues/113) [#114](https://github.com/freeCodeCamp/curriculum/issues/114)
* clarify unclear instructions ([2a7a3fa](https://github.com/freeCodeCamp/curriculum/commit/2a7a3fa))
* incomplete Sass Test ([086a4a0](https://github.com/freeCodeCamp/curriculum/commit/086a4a0))
* penguin colors to match directions ([0f4b8a9](https://github.com/freeCodeCamp/curriculum/commit/0f4b8a9))
* **challenges:** update pseudo-element selector syntax from CSS2 to CSS3 ([15675e8](https://github.com/freeCodeCamp/curriculum/commit/15675e8))
* **challenges:** update RegEx for testcase in es6 challenge ([857b3e9](https://github.com/freeCodeCamp/curriculum/commit/857b3e9))
* **challenges:** update test suite CDN link ([a311e06](https://github.com/freeCodeCamp/curriculum/commit/a311e06))
* **challenges:** updated dates ([21bb9d0](https://github.com/freeCodeCamp/curriculum/commit/21bb9d0)), closes [#17908](https://github.com/freeCodeCamp/curriculum/issues/17908)
* **gitignore file:** added .vscode and unpacked folder to the file ([1b8eb67](https://github.com/freeCodeCamp/curriculum/commit/1b8eb67))
### Features
* **challenge:** add tests for the timestamp microservice challenge ([0cb0da8](https://github.com/freeCodeCamp/curriculum/commit/0cb0da8))
## [3.0.1](https://github.com/freeCodeCamp/curriculum/compare/v3.0.0...v3.0.1) (2018-06-30)
### Bug Fixes
* **challenges:** change comment to make it clearer ([#72](https://github.com/freeCodeCamp/curriculum/issues/72)) ([46fcf43](https://github.com/freeCodeCamp/curriculum/commit/46fcf43))
* **challenges:** fix a test case in an Applied Accessibility ([4c0d587](https://github.com/freeCodeCamp/curriculum/commit/4c0d587))
* **challenges:** remove unnecessary test cases ([17af3dd](https://github.com/freeCodeCamp/curriculum/commit/17af3dd))
* **challenges:** removed a test in basic javascript challenge ([#76](https://github.com/freeCodeCamp/curriculum/issues/76)) ([ff26697](https://github.com/freeCodeCamp/curriculum/commit/ff26697)), closes [#73](https://github.com/freeCodeCamp/curriculum/issues/73)
* **challenges:** removed comment in the seed ([6a8a9db](https://github.com/freeCodeCamp/curriculum/commit/6a8a9db))
* **challenges:** removed redundant text from challenge ([c37a1e8](https://github.com/freeCodeCamp/curriculum/commit/c37a1e8)), closes [#36](https://github.com/freeCodeCamp/curriculum/issues/36)
# [3.0.0](https://github.com/freeCodeCamp/curriculum/compare/v2.0.0...v3.0.0) (2018-06-29)
### Bug Fixes
* **challenge:** Fixed the typo for automatically ([#48](https://github.com/freeCodeCamp/curriculum/issues/48)) ([dd046d6](https://github.com/freeCodeCamp/curriculum/commit/dd046d6))
* **challenge:** Updated tests to avoid confusion ([#57](https://github.com/freeCodeCamp/curriculum/issues/57)) ([7105507](https://github.com/freeCodeCamp/curriculum/commit/7105507))
* **challenges:** change test for template literals challenge ([#37](https://github.com/freeCodeCamp/curriculum/issues/37)) ([4b1c5eb](https://github.com/freeCodeCamp/curriculum/commit/4b1c5eb))
* **challenges:** cherry pick pr 17664 & 17672 from main repo ([#52](https://github.com/freeCodeCamp/curriculum/issues/52)) ([2375d0c](https://github.com/freeCodeCamp/curriculum/commit/2375d0c))
* **challenges:** fixed telephone number validator project ([#53](https://github.com/freeCodeCamp/curriculum/issues/53)) ([2b034e2](https://github.com/freeCodeCamp/curriculum/commit/2b034e2)), closes [#47](https://github.com/freeCodeCamp/curriculum/issues/47)
* **challenges:** fixed typo in css-grid.json ([#46](https://github.com/freeCodeCamp/curriculum/issues/46)) ([e74192e](https://github.com/freeCodeCamp/curriculum/commit/e74192e))
* **challenges:** grammar fix in css-grid auto-fit challenge ([#60](https://github.com/freeCodeCamp/curriculum/issues/60)) ([a6a0266](https://github.com/freeCodeCamp/curriculum/commit/a6a0266))
* **challenges:** Typo errors ([#39](https://github.com/freeCodeCamp/curriculum/issues/39)) ([0c0702d](https://github.com/freeCodeCamp/curriculum/commit/0c0702d))
* **challenges:** update regular expression that fails ([#56](https://github.com/freeCodeCamp/curriculum/issues/56)) ([9fa5907](https://github.com/freeCodeCamp/curriculum/commit/9fa5907)), closes [#55](https://github.com/freeCodeCamp/curriculum/issues/55)
# [2.0.0](https://github.com/freeCodeCamp/curriculum/compare/v1.2.1...v2.0.0) (2018-06-24)
### Bug Fixes
* **challenges:** Correct a regex in ES6 read-only challenge ([#41](https://github.com/freeCodeCamp/curriculum/issues/41)) ([cf9336a](https://github.com/freeCodeCamp/curriculum/commit/cf9336a))
* **challenges:** fix responsive web design cert claim ([6e02f9d](https://github.com/freeCodeCamp/curriculum/commit/6e02f9d))
* **interview-prep:** Remove duplicates ([816be51](https://github.com/freeCodeCamp/curriculum/commit/816be51))
### Features
* **interview-prep:** Porting Rosetta problems ([#17537](https://github.com/freeCodeCamp/curriculum/issues/17537)) ([21930a8](https://github.com/freeCodeCamp/curriculum/commit/21930a8))
## [1.2.1](https://github.com/freeCodeCamp/curriculum/compare/v1.2.0...v1.2.1) (2018-06-21)
### Bug Fixes
* changes text to bold in the JS Algo and DS ([#20](https://github.com/freeCodeCamp/curriculum/issues/20)) ([999c6af](https://github.com/freeCodeCamp/curriculum/commit/999c6af))
* example link will open in new tab ([#22](https://github.com/freeCodeCamp/curriculum/issues/22)) ([5815401](https://github.com/freeCodeCamp/curriculum/commit/5815401))
* give 'Exercise Tracker' the correct id ([6de827c](https://github.com/freeCodeCamp/curriculum/commit/6de827c))
* Remove an unnecessary line from basic javascript challenge ([#19](https://github.com/freeCodeCamp/curriculum/issues/19)) ([e1dfe8f](https://github.com/freeCodeCamp/curriculum/commit/e1dfe8f))
* sample code in intro to currying ([d4cf9de](https://github.com/freeCodeCamp/curriculum/commit/d4cf9de))
* typo errors ([#23](https://github.com/freeCodeCamp/curriculum/issues/23)) ([16ff132](https://github.com/freeCodeCamp/curriculum/commit/16ff132))
# [1.2.0](https://github.com/freeCodeCamp/curriculum/compare/v1.1.3...v1.2.0) (2018-06-19)
### Bug Fixes
* **challenges:** Fix typo in security challenge ([#17608](https://github.com/freeCodeCamp/curriculum/issues/17608)) ([1573455](https://github.com/freeCodeCamp/curriculum/commit/1573455))
* blockquote-formatting-in-challenges ([#17590](https://github.com/freeCodeCamp/curriculum/issues/17590)) ([d31e0a3](https://github.com/freeCodeCamp/curriculum/commit/d31e0a3))
### Features
* **interview-prep:** Porting Rosetta problems ([#17537](https://github.com/freeCodeCamp/curriculum/issues/17537)) ([a133a3f](https://github.com/freeCodeCamp/curriculum/commit/a133a3f))
### Reverts
* "test(challenges): Corrected expected average value" ([#17568](https://github.com/freeCodeCamp/curriculum/issues/17568)) ([20fac4e](https://github.com/freeCodeCamp/curriculum/commit/20fac4e))
## [1.1.3](https://github.com/freeCodeCamp/curriculum/compare/v1.1.2...v1.1.3) (2018-06-13)
### Bug Fixes
* remove extraneous build step ([20c0143](https://github.com/freeCodeCamp/curriculum/commit/20c0143))

427
curriculum/LICENSE.md Normal file
View File

@ -0,0 +1,427 @@
Attribution-ShareAlike 4.0 International
=======================================================================
Creative Commons Corporation ("Creative Commons") is not a law firm and
does not provide legal services or legal advice. Distribution of
Creative Commons public licenses does not create a lawyer-client or
other relationship. Creative Commons makes its licenses and related
information available on an "as-is" basis. Creative Commons gives no
warranties regarding its licenses, any material licensed under their
terms and conditions, or any related information. Creative Commons
disclaims all liability for damages resulting from their use to the
fullest extent possible.
Using Creative Commons Public Licenses
Creative Commons public licenses provide a standard set of terms and
conditions that creators and other rights holders may use to share
original works of authorship and other material subject to copyright
and certain other rights specified in the public license below. The
following considerations are for informational purposes only, are not
exhaustive, and do not form part of our licenses.
Considerations for licensors: Our public licenses are
intended for use by those authorized to give the public
permission to use material in ways otherwise restricted by
copyright and certain other rights. Our licenses are
irrevocable. Licensors should read and understand the terms
and conditions of the license they choose before applying it.
Licensors should also secure all rights necessary before
applying our licenses so that the public can reuse the
material as expected. Licensors should clearly mark any
material not subject to the license. This includes other CC-
licensed material, or material used under an exception or
limitation to copyright. More considerations for licensors:
wiki.creativecommons.org/Considerations_for_licensors
Considerations for the public: By using one of our public
licenses, a licensor grants the public permission to use the
licensed material under specified terms and conditions. If
the licensor's permission is not necessary for any reason--for
example, because of any applicable exception or limitation to
copyright--then that use is not regulated by the license. Our
licenses grant only permissions under copyright and certain
other rights that a licensor has authority to grant. Use of
the licensed material may still be restricted for other
reasons, including because others have copyright or other
rights in the material. A licensor may make special requests,
such as asking that all changes be marked or described.
Although not required by our licenses, you are encouraged to
respect those requests where reasonable. More_considerations
for the public:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
Creative Commons Attribution-ShareAlike 4.0 International Public
License
By exercising the Licensed Rights (defined below), You accept and agree
to be bound by the terms and conditions of this Creative Commons
Attribution-ShareAlike 4.0 International Public License ("Public
License"). To the extent this Public License may be interpreted as a
contract, You are granted the Licensed Rights in consideration of Your
acceptance of these terms and conditions, and the Licensor grants You
such rights in consideration of benefits the Licensor receives from
making the Licensed Material available under these terms and
conditions.
Section 1 -- Definitions.
a. Adapted Material means material subject to Copyright and Similar
Rights that is derived from or based upon the Licensed Material
and in which the Licensed Material is translated, altered,
arranged, transformed, or otherwise modified in a manner requiring
permission under the Copyright and Similar Rights held by the
Licensor. For purposes of this Public License, where the Licensed
Material is a musical work, performance, or sound recording,
Adapted Material is always produced where the Licensed Material is
synched in timed relation with a moving image.
b. Adapter's License means the license You apply to Your Copyright
and Similar Rights in Your contributions to Adapted Material in
accordance with the terms and conditions of this Public License.
c. BY-SA Compatible License means a license listed at
creativecommons.org/compatiblelicenses, approved by Creative
Commons as essentially the equivalent of this Public License.
d. Copyright and Similar Rights means copyright and/or similar rights
closely related to copyright including, without limitation,
performance, broadcast, sound recording, and Sui Generis Database
Rights, without regard to how the rights are labeled or
categorized. For purposes of this Public License, the rights
specified in Section 2(b)(1)-(2) are not Copyright and Similar
Rights.
e. Effective Technological Measures means those measures that, in the
absence of proper authority, may not be circumvented under laws
fulfilling obligations under Article 11 of the WIPO Copyright
Treaty adopted on December 20, 1996, and/or similar international
agreements.
f. Exceptions and Limitations means fair use, fair dealing, and/or
any other exception or limitation to Copyright and Similar Rights
that applies to Your use of the Licensed Material.
g. License Elements means the license attributes listed in the name
of a Creative Commons Public License. The License Elements of this
Public License are Attribution and ShareAlike.
h. Licensed Material means the artistic or literary work, database,
or other material to which the Licensor applied this Public
License.
i. Licensed Rights means the rights granted to You subject to the
terms and conditions of this Public License, which are limited to
all Copyright and Similar Rights that apply to Your use of the
Licensed Material and that the Licensor has authority to license.
j. Licensor means the individual(s) or entity(ies) granting rights
under this Public License.
k. Share means to provide material to the public by any means or
process that requires permission under the Licensed Rights, such
as reproduction, public display, public performance, distribution,
dissemination, communication, or importation, and to make material
available to the public including in ways that members of the
public may access the material from a place and at a time
individually chosen by them.
l. Sui Generis Database Rights means rights other than copyright
resulting from Directive 96/9/EC of the European Parliament and of
the Council of 11 March 1996 on the legal protection of databases,
as amended and/or succeeded, as well as other essentially
equivalent rights anywhere in the world.
m. You means the individual or entity exercising the Licensed Rights
under this Public License. Your has a corresponding meaning.
Section 2 -- Scope.
a. License grant.
1. Subject to the terms and conditions of this Public License,
the Licensor hereby grants You a worldwide, royalty-free,
non-sublicensable, non-exclusive, irrevocable license to
exercise the Licensed Rights in the Licensed Material to:
a. reproduce and Share the Licensed Material, in whole or
in part; and
b. produce, reproduce, and Share Adapted Material.
2. Exceptions and Limitations. For the avoidance of doubt, where
Exceptions and Limitations apply to Your use, this Public
License does not apply, and You do not need to comply with
its terms and conditions.
3. Term. The term of this Public License is specified in Section
6(a).
4. Media and formats; technical modifications allowed. The
Licensor authorizes You to exercise the Licensed Rights in
all media and formats whether now known or hereafter created,
and to make technical modifications necessary to do so. The
Licensor waives and/or agrees not to assert any right or
authority to forbid You from making technical modifications
necessary to exercise the Licensed Rights, including
technical modifications necessary to circumvent Effective
Technological Measures. For purposes of this Public License,
simply making modifications authorized by this Section 2(a)
(4) never produces Adapted Material.
5. Downstream recipients.
a. Offer from the Licensor -- Licensed Material. Every
recipient of the Licensed Material automatically
receives an offer from the Licensor to exercise the
Licensed Rights under the terms and conditions of this
Public License.
b. Additional offer from the Licensor -- Adapted Material.
Every recipient of Adapted Material from You
automatically receives an offer from the Licensor to
exercise the Licensed Rights in the Adapted Material
under the conditions of the Adapter's License You apply.
c. No downstream restrictions. You may not offer or impose
any additional or different terms or conditions on, or
apply any Effective Technological Measures to, the
Licensed Material if doing so restricts exercise of the
Licensed Rights by any recipient of the Licensed
Material.
6. No endorsement. Nothing in this Public License constitutes or
may be construed as permission to assert or imply that You
are, or that Your use of the Licensed Material is, connected
with, or sponsored, endorsed, or granted official status by,
the Licensor or others designated to receive attribution as
provided in Section 3(a)(1)(A)(i).
b. Other rights.
1. Moral rights, such as the right of integrity, are not
licensed under this Public License, nor are publicity,
privacy, and/or other similar personality rights; however, to
the extent possible, the Licensor waives and/or agrees not to
assert any such rights held by the Licensor to the limited
extent necessary to allow You to exercise the Licensed
Rights, but not otherwise.
2. Patent and trademark rights are not licensed under this
Public License.
3. To the extent possible, the Licensor waives any right to
collect royalties from You for the exercise of the Licensed
Rights, whether directly or through a collecting society
under any voluntary or waivable statutory or compulsory
licensing scheme. In all other cases the Licensor expressly
reserves any right to collect such royalties.
Section 3 -- License Conditions.
Your exercise of the Licensed Rights is expressly made subject to the
following conditions.
a. Attribution.
1. If You Share the Licensed Material (including in modified
form), You must:
a. retain the following if it is supplied by the Licensor
with the Licensed Material:
i. identification of the creator(s) of the Licensed
Material and any others designated to receive
attribution, in any reasonable manner requested by
the Licensor (including by pseudonym if
designated);
ii. a copyright notice;
iii. a notice that refers to this Public License;
iv. a notice that refers to the disclaimer of
warranties;
v. a URI or hyperlink to the Licensed Material to the
extent reasonably practicable;
b. indicate if You modified the Licensed Material and
retain an indication of any previous modifications; and
c. indicate the Licensed Material is licensed under this
Public License, and include the text of, or the URI or
hyperlink to, this Public License.
2. You may satisfy the conditions in Section 3(a)(1) in any
reasonable manner based on the medium, means, and context in
which You Share the Licensed Material. For example, it may be
reasonable to satisfy the conditions by providing a URI or
hyperlink to a resource that includes the required
information.
3. If requested by the Licensor, You must remove any of the
information required by Section 3(a)(1)(A) to the extent
reasonably practicable.
b. ShareAlike.
In addition to the conditions in Section 3(a), if You Share
Adapted Material You produce, the following conditions also apply.
1. The Adapter's License You apply must be a Creative Commons
license with the same License Elements, this version or
later, or a BY-SA Compatible License.
2. You must include the text of, or the URI or hyperlink to, the
Adapter's License You apply. You may satisfy this condition
in any reasonable manner based on the medium, means, and
context in which You Share Adapted Material.
3. You may not offer or impose any additional or different terms
or conditions on, or apply any Effective Technological
Measures to, Adapted Material that restrict exercise of the
rights granted under the Adapter's License You apply.
Section 4 -- Sui Generis Database Rights.
Where the Licensed Rights include Sui Generis Database Rights that
apply to Your use of the Licensed Material:
a. for the avoidance of doubt, Section 2(a)(1) grants You the right
to extract, reuse, reproduce, and Share all or a substantial
portion of the contents of the database;
b. if You include all or a substantial portion of the database
contents in a database in which You have Sui Generis Database
Rights, then the database in which You have Sui Generis Database
Rights (but not its individual contents) is Adapted Material,
including for purposes of Section 3(b); and
c. You must comply with the conditions in Section 3(a) if You Share
all or a substantial portion of the contents of the database.
For the avoidance of doubt, this Section 4 supplements and does not
replace Your obligations under this Public License where the Licensed
Rights include other Copyright and Similar Rights.
Section 5 -- Disclaimer of Warranties and Limitation of Liability.
a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
c. The disclaimer of warranties and limitation of liability provided
above shall be interpreted in a manner that, to the extent
possible, most closely approximates an absolute disclaimer and
waiver of all liability.
Section 6 -- Term and Termination.
a. This Public License applies for the term of the Copyright and
Similar Rights licensed here. However, if You fail to comply with
this Public License, then Your rights under this Public License
terminate automatically.
b. Where Your right to use the Licensed Material has terminated under
Section 6(a), it reinstates:
1. automatically as of the date the violation is cured, provided
it is cured within 30 days of Your discovery of the
violation; or
2. upon express reinstatement by the Licensor.
For the avoidance of doubt, this Section 6(b) does not affect any
right the Licensor may have to seek remedies for Your violations
of this Public License.
c. For the avoidance of doubt, the Licensor may also offer the
Licensed Material under separate terms or conditions or stop
distributing the Licensed Material at any time; however, doing so
will not terminate this Public License.
d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
License.
Section 7 -- Other Terms and Conditions.
a. The Licensor shall not be bound by any additional or different
terms or conditions communicated by You unless expressly agreed.
b. Any arrangements, understandings, or agreements regarding the
Licensed Material not stated herein are separate from and
independent of the terms and conditions of this Public License.
Section 8 -- Interpretation.
a. For the avoidance of doubt, this Public License does not, and
shall not be interpreted to, reduce, limit, restrict, or impose
conditions on any use of the Licensed Material that could lawfully
be made without permission under this Public License.
b. To the extent possible, if any provision of this Public License is
deemed unenforceable, it shall be automatically reformed to the
minimum extent necessary to make it enforceable. If the provision
cannot be reformed, it shall be severed from this Public License
without affecting the enforceability of the remaining terms and
conditions.
c. No term or condition of this Public License will be waived and no
failure to comply consented to unless expressly agreed to by the
Licensor.
d. Nothing in this Public License constitutes or may be interpreted
as a limitation upon, or waiver of, any privileges and immunities
that apply to the Licensor or You, including from the legal
processes of any jurisdiction or authority.
=======================================================================
Creative Commons is not a party to its public
licenses. Notwithstanding, Creative Commons may elect to apply one of
its public licenses to material it publishes and in those instances
will be considered the “Licensor.” The text of the Creative Commons
public licenses is dedicated to the public domain under the CC0 Public
Domain Dedication. Except for the limited purpose of indicating that
material is shared under a Creative Commons public license or as
otherwise permitted by the Creative Commons policies published at
creativecommons.org/policies, Creative Commons does not authorize the
use of the trademark "Creative Commons" or any other trademark or logo
of Creative Commons without its prior written consent including,
without limitation, in connection with any unauthorized modifications
to any of its public licenses or any other arrangements,
understandings, or agreements concerning use of licensed material. For
the avoidance of doubt, this paragraph does not form part of the
public licenses.
Creative Commons may be contacted at creativecommons.org.

94
curriculum/README.md Normal file
View File

@ -0,0 +1,94 @@
![freeCodeCamp Social Banner](https://s3.amazonaws.com/freecodecamp/wide-social-banner.png)
# freeCodeCamp Curriculum
[![Build Status](https://travis-ci.org/freeCodeCamp/curriculum.svg?branch=master)](https://travis-ci.org/freeCodeCamp/curriculum) [![npm (scoped)](https://img.shields.io/npm/v/@freecodecamp/curriculum.svg)](https://www.npmjs.com/package/@freecodecamp/curriculum)
[![Pull Requests Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat)](http://makeapullrequest.com)
[![first-timers-only Friendly](https://img.shields.io/badge/first--timers--only-friendly-blue.svg)](http://www.firsttimersonly.com/)
> This package contains the "challenge" files used in the freeCodeCamp Curriculum.
## Installation
```sh
npm i @freecodecamp/curriculum
# or
yarn add @freecodecamp/curriculum
```
## Usage
```js
import { getChallenges } from '@freecodecamp/curriculum';
// fetch an array of blocks
// i.e. basic CSS, functional programming, etc.
getChallenges()
```
### `block` Structure
```js
{
"name": "ES6",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [/*<challenge>*/],
"fileName": "02-javascript-algorithms-and-data-structures/es6.json",
"superBlock": "javascript-algorithms-and-data-structures",
"superOrder": 2
}
```
### `challenge` Structure
```js
{
"id": "ObjectId()",
"title": "Declare a Read-Only Variable with the const Keyword",
"description": [
"A Description of the challenge and what is required to pass"
],
"tests": [
{
"text": "should return \"foo\"",
"testString": "a stringified function using Chai asserts"
}
],
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"Initial editor seed"
],
"head": [
"A place for test set up",
"Can be thought of as mocha's beforeEach()"
],
"tail": [
"A place for test tear down",
"Can be thought of as mocha's afterEach()"
]
}
}
},
```
## Contributing
1. 🍴 Fork this repo
2. 👀️ Follow the contributing guidelines outlined in [Contributing Guidelines](docs/CONTRIBUTING.md).
3. 🔧 Make some awesome changes!
4. 👉 [Make a pull request](https://github.com/freeCodeCamp/learn/compare)
5. 🎉 Get your pull request approved - success!
## License
Copyright (c) 2018 freeCodeCamp.
The curricular content in this repo is licensed under the [CC-BY-SA-4.0](LICENSE.md)

View File

@ -0,0 +1,52 @@
let _ = require('lodash');
function createIsAssert(tapTest, isThing) {
const { assert } = tapTest;
return function() {
const args = [...arguments];
args[0] = isThing(args[0]);
assert.apply(tapTest, args);
};
}
function addAssertsToTapTest(tapTest) {
const assert = tapTest.assert;
assert.isArray = createIsAssert(tapTest, _.isArray);
assert.isBoolean = createIsAssert(tapTest, _.isBoolean);
assert.isString = createIsAssert(tapTest, _.isString);
assert.isNumber = createIsAssert(tapTest, _.isNumber);
assert.isUndefined = createIsAssert(tapTest, _.isUndefined);
assert.deepEqual = tapTest.deepEqual;
assert.equal = tapTest.equal;
assert.strictEqual = tapTest.equal;
assert.sameMembers = function sameMembers() {
const [ first, second, ...args] = arguments;
assert.apply(
tapTest,
[
_.difference(first, second).length === 0 &&
_.difference(second, first).length === 0
].concat(args)
);
};
assert.includeMembers = function includeMembers() {
const [ first, second, ...args] = arguments;
assert.apply(tapTest,
[
_.difference(second, first).length === 0
].concat(args));
};
assert.match = function match() {
const [value, regex, ...args] = arguments;
assert.apply(tapTest,
[
regex.test(value)
].concat(args));
};
return assert;
}
module.exports = addAssertsToTapTest;

View File

@ -0,0 +1,26 @@
import _ from 'lodash';
class ChallengeTitles {
constructor() {
this.knownTitles = [];
}
check(title) {
if (typeof title !== 'string') {
throw new Error(`Expected a valid string for ${title}, but got a(n) ${typeof title}`);
} else if (title.length === 0) {
throw new Error(`Expected a title length greater than 0`);
}
const titleToCheck = title.toLowerCase().replace(/\s+/g, '');
const isKnown = this.knownTitles.includes(titleToCheck);
if (isKnown) {
throw new Error(`
All challenges must have a unique title.
The title ${title} is already assigned
`);
}
this.knownTitles = [ ...this.knownTitles, titleToCheck ];
}
}
export default ChallengeTitles;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,178 @@
{
"name": "Responsive Web Design Projects",
"order": 7,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Build a Tribute Page",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/zNqgVx' target='_blank'>https://codepen.io/freeCodeCamp/full/zNqgVx</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> My tribute page should have an element with a corresponding <code>id=\"main\"</code>, which contains all other elements.",
"<strong>User Story #2:</strong> I should see an element with a corresponding <code>id=\"title\"</code>, which contains a string (i.e. text) that describes the subject of the tribute page (e.g. \"Dr. Norman Borlaug\").",
"<strong>User Story #3:</strong> I should see a <code>div</code> element with a corresponding <code>id=\"img-div\"</code>.",
"<strong>User Story #4:</strong> Within the <code>img-div</code> element, I should see an <code>img</code> element with a corresponding <code>id=\"image\"</code>.",
"<strong>User Story #5:</strong> Within the <code>img-div</code> element, I should see an element with a corresponding <code>id=\"img-caption\"</code> that contains textual content describing the image shown in <code>img-div</code>.",
"<strong>User Story #6:</strong> I should see an element with a corresponding <code>id=\"tribute-info\"</code>, which contains textual content describing the subject of the tribute page.",
"<strong>User Story #7:</strong> I should see an <code>a</code> element with a corresponding <code>id=\"tribute-link\"</code>, which links to an outside site that contains additional information about the subject of the tribute page. HINT: You must give your element an attribute of <code>target</code> and set it to <code>_blank</code> in order for your link to open in a new tab (i.e. <code>target=\"_blank\"</code>).",
"<strong>User Story #8:</strong> The <code>img</code> element should responsively resize, relative to the width of its parent element, without exceeding its original size.",
"<strong>User Story #9:</strong> The <code>img</code> element should be centered within its parent element.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>.",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 1, 2016",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Construye una página Tributo"
},
"pt-br": {
"title": "Construa uma Página Tributo"
},
"ru": {
"title": "Создайте страницу посвященную тому что вас вдохновляет"
}
}
},
{
"id": "587d78af367417b2b2512b03",
"title": "Build a Survey Form",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/VPaoNP' target='_blank'>https://codepen.io/freeCodeCamp/full/VPaoNP</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I can see a title with <code>id=\"title\"</code> in H1 sized text.",
"<strong>User Story #2:</strong> I can see a short explanation with <code>id=\"description\"</code> in P sized text.",
"<strong>User Story #3:</strong> I can see a <code>form</code> with <code>id=\"survey-form\"</code>.",
"<strong>User Story #4:</strong> Inside the form element, I am required to enter my name in a field with <code>id=\"name\"</code>.",
"<strong>User Story #5:</strong> Inside the form element, I am required to enter an email in a field with <code>id=\"email\"</code>.",
"<strong>User Story #6:</strong> If I enter an email that is not formatted correctly, I will see an HTML5 validation error.",
"<strong>User Story #7:</strong> Inside the form, I can enter a number in a field with <code>id=\"number\"</code>.",
"<strong>User Story #8:</strong> If I enter non-numbers in the number input, I will see an HTML5 validation error.",
"<strong>User Story #9:</strong> If I enter numbers outside the range of the number input, which are defined by the <code>min</code> and <code>max</code> attributes, I will see an HTML5 validation error.",
"<strong>User Story #10:</strong> For the name, email, and number input fields inside the form I can see corresponding labels that describe the purpose of each field with the following ids: <code>id=\"name-label\"</code>, <code>id=\"email-label\"</code>, and <code>id=\"number-label\"</code>.",
"<strong>User Story #11:</strong> For the name, email, and number input fields, I can see placeholder text that gives me a description or instructions for each field.",
"<strong>User Story #12:</strong> Inside the form element, I can select an option from a dropdown that has a corresponding <code>id=\"dropdown\"</code>.",
"<strong>User Story #13:</strong> Inside the form element, I can select a field from one or more groups of radio buttons. Each group should be grouped using the <code>name</code> attribute.",
"<strong>User Story #14:</strong> Inside the form element, I can select several fields from a series of checkboxes, each of which must have a <code>value</code> attribute.",
"<strong>User Story #15:</strong> Inside the form element, I am presented with a <code>textarea</code> at the end for additional comments.",
"<strong>User Story #16:</strong> Inside the form element, I am presented with a button with <code>id=\"submit\"</code> to submit all my inputs.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "587d78af367417b2b2512b04",
"title": "Build a Product Landing Page",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/RKRbwL' target='_blank'>https://codepen.io/freeCodeCamp/full/RKRbwL</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> My product landing page should have a <code>header</code> element with a corresponding <code>id=\"header\"</code>.",
"<strong>User Story #2:</strong> I can see an image within the <code>header</code> element with a corresponding <code>id=\"header-img\"</code>. A company logo would make a good image here.",
"<strong>User Story #3:</strong> Within the <code>#header</code> element I can see a <code>nav</code> element with a corresponding <code>id=\"nav-bar\"</code>.",
"<strong>User Story #4:</strong> I can see at least three clickable elements inside the <code>nav</code> element, each with the class <code>nav-link</code>.",
"<strong>User Story #5:</strong> When I click a <code>.nav-link</code> button in the <code>nav</code> element, I am taken to the corresponding section of the landing page.",
"<strong>User Story #6:</strong> I can watch an embedded product video with <code>id=\"video\"</code>.",
"<strong>User Story #7:</strong> My landing page has a <code>form</code> element with a corresponding <code>id=\"form\"</code>.",
"<strong>User Story #8:</strong> Within the form, there is an <code>input</code> field with <code>id=\"email\"</code> where I can enter an email address.",
"<strong>User Story #9:</strong> The <code>#email</code> input field should have placeholder text to let the user know what the field is for.",
"<strong>User Story #10:</strong> The <code>#email</code> input field uses HTML5 validation to confirm that the entered text is an email address.",
"<strong>User Story #11:</strong> Within the form, there is a submit <code>input</code> with a corresponding <code>id=\"submit\"</code>.",
"<strong>User Story #12:</strong> When I click the <code>#submit</code> element, the email is submitted to a static page (use this mock URL: <a href='https://www.freecodecamp.com/email-submit' target='_blank'>https://www.freecodecamp.com/email-submit</a>) that confirms the email address was entered and that it posted successfully.",
"<strong>User Story #13:</strong> The navbar should always be at the top of the viewport.",
"<strong>User Story #14:</strong> My product landing page should have at least one media query.",
"<strong>User Story #15:</strong> My product landing page should utilize CSS flexbox at least once.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/full/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "587d78b0367417b2b2512b05",
"title": "Build a Technical Documentation Page",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/NdrKKL' target='_blank'>https://codepen.io/freeCodeCamp/full/NdrKKL</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I can see a <code>main</code> element with a corresponding <code>id=\"main-doc\"</code>, which contains the page's main content (technical documentation).",
"<strong>User Story #2:</strong> Within the <code>#main-doc</code> element, I can see several <code>section</code> elements, each with a class of <code>main-section</code>. There should be a minimum of 5.",
"<strong>User Story #3:</strong> The first element within each <code>.main-section</code> should be a <code>header</code> element which contains text that describes the topic of that section.",
"<strong>User Story #4:</strong> Each <code>section</code> element with the class of <code>main-section</code> should also have an id that corresponds with the text of each <code>header</code> contained within it. Any spaces should be replaced with underscores (e.g. The <code>section</code> that contains the header \"Javascript and Java\" should have a corresponding <code>id=\"Javascript_and_Java\"</code>).",
"<strong>User Story #5:</strong> The <code>.main-section</code> elements should contain at least 10 <code>p</code> elements total (not each).",
"<strong>User Story #6:</strong> The <code>.main-section</code> elements should contain at least 5 <code>code</code> elements total (not each).",
"<strong>User Story #7:</strong> The <code>.main-section</code> elements should contain at least 5 <code>li</code> items total (not each).",
"<strong>User Story #8:</strong> I can see a <code>nav</code> element with a corresponding <code>id=\"navbar\"</code>.",
"<strong>User Story #9:</strong> The navbar element should contain one <code>header</code> element which contains text that describes the topic of the technical documentation.",
"<strong>User Story #10:</strong> Additionally, the navbar should contain link (<code>a</code>) elements with the class of <code>nav-link</code>. There should be one for every element with the class <code>main-section</code>.",
"<strong>User Story #11:</strong> The <code>header</code> element in the navbar must come before any link (<code>a</code>) elements in the navbar.",
"<strong>User Story #12:</strong> Each element with the class of <code>nav-link</code> should contain text that corresponds to the <code>header</code> text within each <code>section</code> (e.g. if you have a \"Hello world\" section/header, your navbar should have an element which contains the text \"Hello world\").",
"<strong>User Story #13:</strong> When I click on a navbar element, the page should navigate to the corresponding section of the <code>main-doc</code> element (e.g. If I click on a <code>nav-link</code> element that contains the text \"Hello world\", the page navigates to a <code>section</code> element that has that id and contains the corresponding <code>header</code>.",
"<strong>User Story #14:</strong> On regular sized devices (laptops, desktops), the element with <code>id=\"navbar\"</code> should be shown on the left side of the screen and should always be visible to the user.",
"<strong>User Story #15:</strong> My Technical Documentation page should use at least one media query.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 15, 2017",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {}
},
{
"id": "bd7158d8c242eddfaeb5bd13",
"title": "Build a Personal Portfolio Webpage",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/zNBOYG' target='_blank'>https://codepen.io/freeCodeCamp/full/zNBOYG</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, and CSS to complete this project. Plain CSS is recommended because that is what the lessons have covered so far and you should get some practice with plain CSS. You can use Bootstrap or SASS if you choose. Additional technologies (just for example jQuery, React, Angular, or Vue) are not recommended for this project, and using them is at your own risk. Other projects will give you a chance to work with different technology stacks like React. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> My portfolio should have a welcome section with an id of <code>welcome-section</code>.",
"<strong>User Story #2:</strong> The welcome section should have an <code>h1</code> element that contains text.",
"<strong>User Story #3:</strong> My portfolio should have a projects section with an id of <code>projects</code>.",
"<strong>User Story #4:</strong> The projects section should contain at least one element with a class of <code>project-tile</code> to hold a project.",
"<strong>User Story #5:</strong> The projects section should contain at least one link to a project.",
"<strong>User Story #6:</strong> My portfolio should have a navbar with an id of <code>navbar</code>.",
"<strong>User Story #7:</strong> The navbar should contain at least one link that I can click on to navigate to different sections of the page.",
"<strong>User Story #8:</strong> My portfolio should have a link with an id of <code>profile-link</code>, which opens my GitHub or FCC profile in a new tab.",
"<strong>User Story #9:</strong> My portfolio should have at least one media query.",
"<strong>User Story #10:</strong> The height of the welcome section should be equal to the height of the viewport.",
"<strong>User Story #11:</strong> The navbar should always be at the top of the viewport.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Construye una página web para tu portafolio"
},
"pt-br": {
"title": "Construa uma Página de Portfólio Pessoal"
},
"ru": {
"title": "Создайте сайт-портфолио"
}
}
}
]
}

View File

@ -0,0 +1,244 @@
{
"name": "Responsive Web Design Principles",
"order": 4,
"time": "1 hour",
"helpRoom": "Help",
"challenges": [
{
"id": "587d78b0367417b2b2512b08",
"title": "Create a Media Query",
"description": [
"Media Queries are a new technique introduced in CSS3 that change the presentation of content based on different viewport sizes. The viewport is a user's visible area of a web page, and is different depending on the device used to access the site.",
"Media Queries consist of a media type, and if that media type matches the type of device the document is displayed on, the styles are applied. You can have as many selectors and styles inside your media query as you want.",
"Here's an example of a media query that returns the content when the device's width is less than or equal to 100px:",
"<code>@media (max-width: 100px) { /* CSS Rules */ }</code>",
"and the following media query returns the content when the device's height is more than or equal to 350px:",
"<code>@media (min-height: 350px) { /* CSS Rules */ }</code>",
"Remember, the CSS inside the media query is applied only if the media type matches that of the device being used.",
"<hr>",
"Add a media query, so that the <code>p</code> tag has a <code>font-size</code> of 10px when the device's height is less than or equal to 800px."
],
"tests": [
{
"text": "Your <code>p</code> element should have the <code>font-size</code> of 10px when the device <code>height</code> is less than or equal to 800px.",
"testString": "assert($('p').css('font-size') == '10px', 'Your <code>p</code> element should have the <code>font-size</code> of 10px when the device <code>height</code> is less than or equal to 800px.');"
},
{
"text": "Declare a <code>@media</code> query for devices with a <code>height</code> less than or equal to 800px.",
"testString": "assert(code.match(/@media\\s*?\\(\\s*?max-height\\s*?:\\s*?800px\\s*?\\)/g), 'Declare a <code>@media</code> query for devices with a <code>height</code> less than or equal to 800px.');"
}
],
"releasedOn": "Feb 17, 2017",
"solutions": [],
"hints": [],
"challengeType": 0,
"translations": {
"pt-br": {
"title": "Criando uma Media Query",
"description": [
"Media Queries são uma nova técnica introduzida no CSS3 que mudam a apresentação do conteúdo de acordo com os diferentes tamanhos de janela de exibição. A janela de exibição é a área visível de uma página da web, e é diferente dependendo do dispositivo utilizado para acessar o site.",
"Media Queries consistem em um tipo de mídia, e se o tipo de mídia corresponder com o dispositivo no qual o documento está sendo exibido, os estilos são aplicados. Você pode colocar quantos seletores e estilos quanto desejar dentro de suas media queries.",
"Segue um exemplo de media query que retorna seu conteúdo quando a largura do dispositivo é menor que 100px:",
"<code>@media (max-width: 100px) { /* Regras do CSS */ }</code>",
"Lembre-se, o CSS dentro da media query só é aplicado se o tipo de mídia corresponder ao dispositivo em uso.",
"<hr>",
"Adicione uma media query para que o tag <code>p</code> tenha um <code>font-size</code> de 10px quando a altura do dispositivo for menor ou igual a 800px."
]
}
},
"videoUrl": "https://scrimba.com/p/pzrPu4/cqwKrtm",
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style>",
" p {",
" font-size: 20px;",
" }",
" ",
" /* Add media query below */",
" ",
"</style>",
" ",
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d78b1367417b2b2512b09",
"title": "Make an Image Responsive",
"description": [
"Making images responsive with CSS is actually very simple. Instead of applying an absolute width to an element:",
"<code>img { width: 720px; }</code>",
"You can use:",
"<blockquote>img {<br>&nbsp;&nbsp;max-width: 100%;<br>&nbsp;&nbsp;display: block;<br>&nbsp;&nbsp;height: auto;<br>}</blockquote>",
"The <code>max-width</code> property of 100% scales the image to fit the width of its container, but the image won't stretch wider than its original width. Setting the <code>display</code> property to block changes the image from an inline element (its default), to a block element on its own line. The <code>height</code> property of auto keeps the original aspect ratio of the image.",
"<hr>",
"Add style rules for the <code>img</code> tag to make it responsive to the size of its container. It should display as a block-level element, it should fit the full width of its container without stretching, and it should keep its original aspect ratio."
],
"tests": [
{
"text": "Your <code>img</code> tag should have a <code>max-width</code> set to 100%.",
"testString": "assert(code.match(/max-width:\\s*?100%;/g), 'Your <code>img</code> tag should have a <code>max-width</code> set to 100%.');"
},
{
"text": "Your <code>img</code> tag should have a <code>display</code> set to block.",
"testString": "assert($('img').css('display') == 'block', 'Your <code>img</code> tag should have a <code>display</code> set to block.');"
},
{
"text": "Your <code>img</code> tag should have a <code>height</code> set to auto.",
"testString": "assert(code.match(/height:\\s*?auto;/g), 'Your <code>img</code> tag should have a <code>height</code> set to auto.');"
}
],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"solutions": [],
"hints": [],
"translations": {
"pt-br": {
"title": "Torne uma Imagem Responsiva",
"description": [
"Fazer com que imagens sejam responsivas é muito simples com CSS. Ao invés de aplicar uma largura absoluta a um elemento:",
"<code>img { width: 720px; }</code>",
"Você pode usar:",
"<blockquote>img {<br>&nbsp;&nbsp;max-width: 100%;<br>&nbsp;&nbsp;display: block;<br>&nbsp;&nbsp;height: auto;<br>}</blockquote>",
"A propriedade <code>max-width</code> em 100% ajusta o tamanho da imagem para preencher a largura de seu container, mas a imagem não irá esticar mais que sua largura original. Ajustando a propriedade <code>display</code> como block muda imagem de elemento inline (o padrão) para um elemento block com uma linha própria. A propriedade <code>height</code> na configuração auto mantem a proporção original da imagem.",
"<hr>",
"Adicione regras de estilo para a tag <code>img</code> para torná-la responsiva com relação ao tamanho do seu container. Ela deve ser exibida como um elemento de nível block, e deve preencher toda a largura de seu container sem esticar, mantendo as proporções originais."
]
}
},
"videoUrl": "https://scrimba.com/p/pzrPu4/cz763UD",
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style>",
" ",
"</style>",
"",
"<img src=\"https://s3.amazonaws.com/freecodecamp/FCCStickerPack.jpg\" alt=\"freeCodeCamp stickers set\">"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d78b1367417b2b2512b0a",
"title": "Use a Retina Image for Higher Resolution Displays",
"description": [
"The simplest way to make your images appear \"retina\" (and optimize them for retina displays) is to define their <code>width</code> and <code>height</code> values as only half of what the original file is.",
"Here is an example of an image that is only using half of the original height and width:",
"<blockquote>&lt;style&gt;<br>&nbsp;&nbsp;img { height: 250px; width: 250px; }<br>&lt;/style&gt;<br>&lt;img src=&quot;coolPic500x500&quot; alt=&quot;A most excellent picture&quot;&gt;</blockquote>",
"<hr>",
"Set the <code>width</code> and <code>height</code> of the <code>img</code> tag to half of their original values. In this case, both the original <code>height</code> and the original <code>width</code> are 200px."
],
"tests": [
{
"text": "Your <code>img</code> tag should have a <code>width</code> of 100 pixels.",
"testString": "assert($('img').css('width') == '100px', 'Your <code>img</code> tag should have a <code>width</code> of 100 pixels.');"
},
{
"text": "Your <code>img</code> tag should have a <code>height</code> of 100 pixels.",
"testString": "assert($('img').css('height') == '100px', 'Your <code>img</code> tag should have a <code>height</code> of 100 pixels.');"
}
],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"solutions": [],
"hints": [],
"translations": {
"pt-br": {
"title": "Use uma Imagem Retina para Telas de Alta Resolução",
"description": [
"A maneira mais simples de fazer com que suas imagens tenham uma aparência \"retina\" (e otimizadas para telas retina) é definindo seus valores de <code>width</code> e <code>height</code> como somente metade do tamanho original dos arquivos.",
"Segue um exemplo de imagem que possui somente metade dos valores originais de altura e largura:",
"<blockquote>&lt;style&gt;<br>&nbsp;&nbsp;img { height: 250px; width: 250px; }<br>&lt;/style&gt;<br>&lt;img src=&quot;coolPic500x500&quot; alt=&quot;A most excellent picture&quot;&gt;</blockquote>",
"<hr>",
"Configure os valores de <code>width</code> e <code>height</code> da tag <code>img</code> como metade do seu tamanho original. Nesse caso, o valor original de <code>height</code> e o valor original de <code>width</code> são de 200px."
]
}
},
"videoUrl": "https://scrimba.com/p/pzrPu4/cVZ4Rfp",
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style>",
" ",
"</style>",
"",
"<img src=\"https://s3.amazonaws.com/freecodecamp/FCCStickers-CamperBot200x200.jpg\" alt=\"freeCodeCamp sticker that says 'Because CamperBot Cares'\">"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d78b1367417b2b2512b0c",
"title": "Make Typography Responsive",
"description": [
"Instead of using <code>em</code> or <code>px</code> to size text, you can use viewport units for responsive typography. Viewport units, like percentages, are relative units, but they are based off different items. Viewport units are relative to the viewport dimensions (width or height) of a device, and percentages are relative to the size of the parent container element.",
"The four different viewport units are:",
"<ul><li><code>vw: 10vw</code> would be 10% of the viewport's width.</li><li><code>vh: 3vh</code> would be 3% of the viewport's height.</li><li><code>vmin: 70vmin</code> would be 70% of the viewport's smaller dimension (height vs. width).</li><li><code>vmax: 100vmax</code> would be 100% of the viewport's bigger dimension (height vs. width).</li></ul>",
"<hr>",
"Set the <code>width</code> of the <code>h2</code> tag to 80% of the viewport's width and the <code>width</code> of the paragraph as 75% of the viewport's smaller dimension."
],
"tests": [
{
"text": "Your <code>h2</code> tag should have a <code>width</code> of 80vw.",
"testString": "assert(code.match(/h2\\s*?{\\s*?width:\\s*?80vw;\\s*?}/g), 'Your <code>h2</code> tag should have a <code>width</code> of 80vw.');"
},
{
"text": "Your <code>p</code> tag should have a <code>width</code> of 75vmin.",
"testString": "assert(code.match(/p\\s*?{\\s*?width:\\s*?75vmin;\\s*?}/g), 'Your <code>p</code> tag should have a <code>width</code> of 75vmin.');"
}
],
"releasedOn": "Feb 17, 2017",
"solutions": ["var code = \"h2 {width: 80vw;} p {width: 75vmin;}\""],
"hints": [],
"challengeType": 0,
"translations": {
"pt-br": {
"title": "Torne a Tipografia Responsiva",
"description": [
"Ao invés de utilizar <code>em</code> ou <code>px</code> para alterar o tamanho do texto, você pode usar unidades da janela de exibição para obter tipografia responsiva. Unidades da janela de exibição, assim como porcentagens, são unidades relativas, mas que são baseadas em ítens diferentes. Unidades da janela de exibição são relativas às dimensões da janela de exibição (largura ou altura) de um dispositivo, enquanto que porcentagens são relativas ao tamanho do container do elemento pai.",
"As quatro unidades da janela de exibição são",
"<ul><li><code>vw: 10vw</code> seria 10% da largura da janela de exibição.</li><li><code>vh: 3vh</code> seria 3% da altura da janela de exibição.</li><li><code>vmin: 70vmin</code> seria 70% da menor dimensão da janela de exibição (largura ou altura).</li><li><code>vmax: 100vmax</code> seria 100% da maior dimensão da janela de exibição (largura ou altura).</li></ul>",
"<hr>",
"Ajuste o <code>width</code> da tag <code>h2</code> para 80% da largura da janela de exibição e a <code>width</code> do parágrafo para 75% da menor dimensão da janela de exibição."
]
}
},
"videoUrl": "https://scrimba.com/p/pzrPu4/crzN7T8",
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style>",
" ",
"</style>",
"",
"<h2>Importantus Ipsum</h2>",
"<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus quis tempus massa. Aenean erat nisl, gravida vel vestibulum cursus, interdum sit amet lectus. Sed sit amet quam nibh. Suspendisse quis tincidunt nulla. In hac habitasse platea dictumst. Ut sit amet pretium nisl. Vivamus vel mi sem. Aenean sit amet consectetur sem. Suspendisse pretium, purus et gravida consequat, nunc ligula ultricies diam, at aliquet velit libero a dui.</p>"
],
"head": [],
"tail": []
}
}
}
]
}

View File

@ -0,0 +1,588 @@
{
"name": "Debugging",
"order": 4,
"time": "1 hour",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7b83367417b2b2512b33",
"title": "Use the JavaScript Console to Check the Value of a Variable",
"description": [
"Both Chrome and Firefox have excellent JavaScript consoles, also known as DevTools, for debugging your JavaScript.",
"You can find Developer tools in your Chrome's menu or Web Console in FireFox's menu. If you're using a different browser, or a mobile phone, we strongly recommend switching to desktop Firefox or Chrome.",
"The <code>console.log()</code> method, which \"prints\" the output of what's within its parentheses to the console, will likely be the most helpful debugging tool. Placing it at strategic points in your code can show you the intermediate values of variables. It's good practice to have an idea of what the output should be before looking at what it is. Having check points to see the status of your calculations throughout your code will help narrow down where the problem is.",
"Here's an example to print 'Hello world!' to the console:",
"<code>console.log('Hello world!');</code>",
"<hr>",
"Use the <code>console.log()</code> method to print the value of the variable <code>a</code> where noted in the code."
],
"tests": [
{
"text": "Your code should use <code>console.log()</code> to check the value of the variable <code>a</code>.",
"testString": "assert(code.match(/console\\.log\\(a\\)/g), 'Your code should use <code>console.log()</code> to check the value of the variable <code>a</code>.');"
}
],
"solutions": ["var a = 5; console.log(a);"],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let a = 5;",
"let b = 1;",
"a++;",
"// Add your code below this line",
"",
"",
"let sumAB = a + b;",
"console.log(sumAB);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b83367417b2b2512b37",
"title": "Understanding the Differences between the freeCodeCamp and Browser Console",
"description": [
"You may have noticed that some freeCodeCamp JavaScript challenges include their own console. This console behaves a little differently than the browser console you used in the last challenge.",
"The following challenge is meant to highlight some of the differences between the freeCodeCamp console and the browser console.",
"First, the browser console. When you load and run an ordinary JavaScript file in your browser the <code>console.log()</code> statements will print exactly what you tell them to print to the browser console the exact number of times you requested. In your in-browser text editor the process is slightly different and can be confusing at first.",
"Values passed to <code>console.log()</code> in the text editor block run each set of tests as well as one more time for any function calls that you have in your code.",
"This lends itself to some interesting behavior and might trip you up in the beginning, because a logged value that you expect to see only once may print out many more times depending on the number of tests and the values being passed to those tests.",
"If you would like to see only your single output and not have to worry about running through the test cycles, you can use <code>console.clear()</code>.",
"<hr>",
"Use <code>console.log()</code> to print the variables in the code where indicated.",
""
],
"tests": [
{
"text": "Use <code>console.log()</code> to print the <code>outputTwo</code> variable. In your Browser Console this should print out the value of the variable two times.",
"testString": "assert(code.match(/console\\.log\\(outputTwo\\)/g), 'Use <code>console.log()</code> to print the <code>outputTwo</code> variable. In your Browser Console this should print out the value of the variable two times.');"
},
{
"text": "Use <code>console.log()</code> to print the <code>outputOne</code> variable.",
"testString": "assert(code.match(/console\\.log\\(outputOne\\)/g), 'Use <code>console.log()</code> to print the <code>outputOne</code> variable.');"
},
{
"text": "Use <code>console.clear()</code> to modify your output so that <code>outputOne</code> variable only outputs once.",
"testString": "assert(code.match(/^(\\s*console.clear\\(\\);?\\s*)$/gm), 'Use <code>console.clear()</code> to modify your output so that <code>outputOne</code> variable only outputs once.');"
}
],
"solutions": [
"let outputTwo = \"This will print to the browser console 2 times\"; console.log(outputTwo); let outputOne = \"Try to get this to log only once to the browser console\";\nconsole.clear();\nconsole.log(outputOne);"
],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"// Open your browser console",
"let outputTwo = \"This will print to the browser console 2 times\";",
"// Use console.log() to print the outputTwo variable",
"",
"",
"let outputOne = \"Try to get this to log only once to the browser console\";",
"// Use console.clear() in the next line to print the outputOne only once",
"",
"",
"// Use console.log() to print the outputOne variable",
"",
""
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b84367417b2b2512b34",
"title": "Use typeof to Check the Type of a Variable",
"description": [
"You can use <code>typeof</code> to check the data structure, or type, of a variable. This is useful in debugging when working with multiple data types. If you think you're adding two numbers, but one is actually a string, the results can be unexpected. Type errors can lurk in calculations or function calls. Be careful especially when you're accessing and working with external data in the form of a JavaScript Object Notation (JSON) object.",
"Here are some examples using <code>typeof</code>:",
"<blockquote>console.log(typeof \"\"); // outputs \"string\"<br>console.log(typeof 0); // outputs \"number\"<br>console.log(typeof []); // outputs \"object\"<br>console.log(typeof {}); // outputs \"object\"</blockquote>",
"JavaScript recognizes six primitive (immutable) data types: <code>Boolean</code>, <code>Null</code>, <code>Undefined</code>, <code>Number</code>, <code>String</code>, and <code>Symbol</code> (new with ES6) and one type for mutable items: <code>Object</code>. Note that in JavaScript, arrays are technically a type of object.",
"<hr>",
"Add two <code>console.log()</code> statements to check the <code>typeof</code> each of the two variables <code>seven</code> and <code>three</code> in the code."
],
"tests": [
{
"text": "Your code should use <code>typeof</code> in two <code>console.log()</code> statements to check the type of the variables.",
"testString": "assert(code.match(/console\\.log\\(typeof[\\( ].*\\)?\\)/g).length == 2, 'Your code should use <code>typeof</code> in two <code>console.log()</code> statements to check the type of the variables.');"
},
{
"text": "Your code should use <code>typeof</code> to check the type of the variable <code>seven</code>.",
"testString": "assert(code.match(/typeof[\\( ]seven\\)?/g), 'Your code should use <code>typeof</code> to check the type of the variable <code>seven</code>.');"
},
{
"text": "Your code should use <code>typeof</code> to check the type of the variable <code>three</code>.",
"testString": "assert(code.match(/typeof[\\( ]three\\)?/g), 'Your code should use <code>typeof</code> to check the type of the variable <code>three</code>.');"
}
],
"solutions": [
"let seven = 7;let three = \"3\";console.log(typeof seven);\nconsole.log(typeof three);"
],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let seven = 7;",
"let three = \"3\";",
"console.log(seven + three);",
"// Add your code below this line",
""
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b84367417b2b2512b35",
"title": "Catch Misspelled Variable and Function Names",
"description": [
"The <code>console.log()</code> and <code>typeof</code> methods are the two primary ways to check intermediate values and types of program output. Now it's time to get into the common forms that bugs take. One syntax-level issue that fast typers can commiserate with is the humble spelling error.",
"Transposed, missing, or mis-capitalized characters in a variable or function name will have the browser looking for an object that doesn't exist - and complain in the form of a reference error. JavaScript variable and function names are case-sensitive.",
"<hr>",
"Fix the two spelling errors in the code so the <code>netWorkingCapital</code> calculation works."
],
"tests": [
{
"text": "Check the spelling of the two variables used in the netWorkingCapital calculation, the console output should show that \"Net working capital is: 2\".",
"testString": "assert(netWorkingCapital === 2, 'Check the spelling of the two variables used in the netWorkingCapital calculation, the console output should show that \"Net working capital is: 2\".');"
},
{
"text": "There should be no instances of mis-spelled variables in the code.",
"testString": "assert(!code.match(/recievables/g), 'There should be no instances of mis-spelled variables in the code.');"
},
{
"text": "The <code>receivables</code> variable should be declared and used properly in the code.",
"testString": "assert(code.match(/receivables/g).length == 2, 'The <code>receivables</code> variable should be declared and used properly in the code.');"
},
{
"text": "There should be no instances of mis-spelled variables in the code.",
"testString": "assert(!code.match(/payable;/g), 'There should be no instances of mis-spelled variables in the code.');"
},
{
"text": "The <code>payables</code> variable should be declared and used properly in the code.",
"testString": "assert(code.match(/payables/g).length == 2, 'The <code>payables</code> variable should be declared and used properly in the code.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let receivables = 10;",
"let payables = 8;",
"let netWorkingCapital = recievables - payable;",
"console.log(`Net working capital is: ${netWorkingCapital}`);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b84367417b2b2512b36",
"title": "Catch Unclosed Parentheses, Brackets, Braces and Quotes",
"description": [
"Another syntax error to be aware of is that all opening parentheses, brackets, curly braces, and quotes have a closing pair. Forgetting a piece tends to happen when you're editing existing code and inserting items with one of the pair types. Also, take care when nesting code blocks into others, such as adding a callback function as an argument to a method.",
"One way to avoid this mistake is as soon as the opening character is typed, immediately include the closing match, then move the cursor back between them and continue coding. Fortunately, most modern code editors generate the second half of the pair automatically.",
"<hr>",
"Fix the two pair errors in the code."
],
"tests": [
{
"text": "Your code should fix the missing piece of the array.",
"testString": "assert(code.match(/myArray\\s*?=\\s*?\\[\\s*?1\\s*?,\\s*?2\\s*?,\\s*?3\\s*?\\];/g), 'Your code should fix the missing piece of the array.');"
},
{
"text": "Your code should fix the missing piece of the <code>.reduce()</code> method. The console output should show that \"Sum of array values is: 6\".",
"testString": "assert(arraySum === 6, 'Your code should fix the missing piece of the <code>.reduce()</code> method. The console output should show that \"Sum of array values is: 6\".');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let myArray = [1, 2, 3;",
"let arraySum = myArray.reduce((previous, current => previous + current);",
"console.log(`Sum of array values is: ${arraySum}`);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b84367417b2b2512b37",
"title": "Catch Mixed Usage of Single and Double Quotes",
"description": [
"JavaScript allows the use of both single ('') and double (\"\") quotes to declare a string. Deciding which one to use generally comes down to personal preference, with some exceptions.",
"Having two choices is great when a string has contractions or another piece of text that's in quotes. Just be careful that you don't close the string too early, which causes a syntax error.",
"Here are some examples of mixing quotes:",
"<blockquote>// These are correct:<br>const grouchoContraction = \"I've had a perfectly wonderful evening, but this wasn't it.\";<br>const quoteInString = \"Groucho Marx once said 'Quote me as saying I was mis-quoted.'\";<br>// This is incorrect:<br>const uhOhGroucho = 'I've had a perfectly wonderful evening, but this wasn't it.';</blockquote>",
"Of course, it is okay to use only one style of quotes. You can escape the quotes inside the string by using the backslash (\\) escape character:",
"<blockquote>// Correct use of same quotes:<br>const allSameQuotes = 'I\\'ve had a perfectly wonderful evening, but this wasn\\'t it.';</blockquote>",
"<hr>",
"Fix the string so it either uses different quotes for the <code>href</code> value, or escape the existing ones. Keep the double quote marks around the entire string."
],
"tests": [
{
"text": "Your code should fix the quotes around the <code>href</code> value \"#Home\" by either changing or escaping them.",
"testString": "assert(code.match(/<a href=\\s*?('|\\\\\")#Home\\1\\s*?>/g), 'Your code should fix the quotes around the <code>href</code> value \"#Home\" by either changing or escaping them.');"
},
{
"text": "Your code should keep the double quotes around the entire string.",
"testString": "assert(code.match(/\"<p>.*?<\\/p>\";/g), 'Your code should keep the double quotes around the entire string.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let innerHtml = \"<p>Click here to <a href=\"#Home\">return home</a></p>\";",
"console.log(innerHtml);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b85367417b2b2512b38",
"title": "Catch Use of Assignment Operator Instead of Equality Operator",
"description": [
"Branching programs, i.e. ones that do different things if certain conditions are met, rely on <code>if</code>, <code>else if</code>, and <code>else</code> statements in JavaScript. The condition sometimes takes the form of testing whether a result is equal to a value.",
"This logic is spoken (in English, at least) as \"if x equals y, then ...\" which can literally translate into code using the <code>=</code>, or assignment operator. This leads to unexpected control flow in your program.",
"As covered in previous challenges, the assignment operator (<code>=</code>) in JavaScript assigns a value to a variable name. And the <code>==</code> and <code>===</code> operators check for equality (the triple <code>===</code> tests for strict equality, meaning both value and type are the same).",
"The code below assigns <code>x</code> to be 2, which evaluates as <code>true</code>. Almost every value on its own in JavaScript evaluates to <code>true</code>, except what are known as the \"falsy\" values: <code>false</code>, <code>0</code>, <code>\"\"</code> (an empty string), <code>NaN</code>, <code>undefined</code>, and <code>null</code>.",
"<blockquote>let x = 1;<br>let y = 2;<br>if (x = y) {<br>&nbsp;&nbsp;// this code block will run for any value of y (unless y were originally set as a falsy)<br>} else {<br>&nbsp;&nbsp;// this code block is what should run (but won't) in this example<br>}</blockquote>",
"<hr>",
"Fix the condition so the program runs the right branch, and the appropriate value is assigned to <code>result</code>."
],
"tests": [
{
"text": "Your code should fix the condition so it checks for equality, instead of using assignment.",
"testString": "assert(result == \"Not equal!\", 'Your code should fix the condition so it checks for equality, instead of using assignment.');"
},
{
"text": "The condition can use either <code>==</code> or <code>===</code> to test for equality.",
"testString": "assert(code.match(/x\\s*?===?\\s*?y/g), 'The condition can use either <code>==</code> or <code>===</code> to test for equality.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"let x = 7;",
"let y = 9;",
"let result = \"to come\";",
"",
"if(x = y) {",
" result = \"Equal!\";",
"} else {",
" result = \"Not equal!\";",
"}",
"",
"console.log(result);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b85367417b2b2512b39",
"title": "Catch Missing Open and Closing Parenthesis After a Function Call",
"description": [
"When a function or method doesn't take any arguments, you may forget to include the (empty) opening and closing parentheses when calling it. Often times the result of a function call is saved in a variable for other use in your code. This error can be detected by logging variable values (or their types) to the console and seeing that one is set to a function reference, instead of the expected value the function returns.",
"The variables in the following example are different:",
"<blockquote>function myFunction() {<br>&nbsp;&nbsp;return \"You rock!\";<br>}<br>let varOne = myFunction; // set to equal a function<br>let varTwo = myFunction(); // set to equal the string \"You rock!\"</blockquote>",
"<hr>",
"Fix the code so the variable <code>result</code> is set to the value returned from calling the function <code>getNine</code>."
],
"tests": [
{
"text": "Your code should fix the variable <code>result</code> so it is set to the number that the function <code>getNine</code> returns.",
"testString": "assert(result == 9, 'Your code should fix the variable <code>result</code> so it is set to the number that the function <code>getNine</code> returns.');"
},
{
"text": "Your code should call the <code>getNine</code> function.",
"testString": "assert(code.match(/getNine\\(\\)/g).length == 2, 'Your code should call the <code>getNine</code> function.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function getNine() {",
" let x = 6;",
" let y = 3;",
" return x + y;",
"}",
"",
"let result = getNine;",
"console.log(result);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b85367417b2b2512b3a",
"title": "Catch Arguments Passed in the Wrong Order When Calling a Function",
"description": [
"Continuing the discussion on calling functions, the next bug to watch out for is when a function's arguments are supplied in the incorrect order. If the arguments are different types, such as a function expecting an array and an integer, this will likely throw a runtime error. If the arguments are the same type (all integers, for example), then the logic of the code won't make sense. Make sure to supply all required arguments, in the proper order to avoid these issues.",
"<hr>",
"The function <code>raiseToPower</code> raises a base to an exponent. Unfortunately, it's not called properly - fix the code so the value of <code>power</code> is the expected 8."
],
"tests": [
{
"text": "Your code should fix the variable <code>power</code> so it equals 2 raised to the 3rd power, not 3 raised to the 2nd power.",
"testString": "assert(power == 8, 'Your code should fix the variable <code>power</code> so it equals 2 raised to the 3rd power, not 3 raised to the 2nd power.');"
},
{
"text": "Your code should use the correct order of the arguments for the <code>raiseToPower</code> function call.",
"testString": "assert(code.match(/raiseToPower\\(\\s*?base\\s*?,\\s*?exp\\s*?\\);/g), 'Your code should use the correct order of the arguments for the <code>raiseToPower</code> function call.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function raiseToPower(b, e) {",
" return Math.pow(b, e);",
"}",
"",
"let base = 2;",
"let exp = 3;",
"let power = raiseToPower(exp, base);",
"console.log(power);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b86367417b2b2512b3b",
"title": "Catch Off By One Errors When Using Indexing",
"description": [
"<code>Off by one errors</code> (sometimes called OBOE) crop up when you're trying to target a specific index of a string or array (to slice or access a segment), or when looping over the indices of them. JavaScript indexing starts at zero, not one, which means the last index is always one less than the length of the item. If you try to access an index equal to the length, the program may throw an \"index out of range\" reference error or print <code>undefined</code>.",
"When you use string or array methods that take index ranges as arguments, it helps to read the documentation and understand if they are inclusive (the item at the given index is part of what's returned) or not. Here are some examples of off by one errors:",
"<blockquote>let alphabet = \"abcdefghijklmnopqrstuvwxyz\";<br>let len = alphabet.length;<br>for (let i = 0; i <= len; i++) {<br>&nbsp;&nbsp;// loops one too many times at the end<br>&nbsp;&nbsp;console.log(alphabet[i]);<br>}<br>for (let j = 1; j < len; j++) {<br>&nbsp;&nbsp;// loops one too few times and misses the first character at index 0<br>&nbsp;&nbsp;console.log(alphabet[j]);<br>}<br>for (let k = 0; k < len; k++) {<br>&nbsp;&nbsp;// Goldilocks approves - this is just right<br>&nbsp;&nbsp;console.log(alphabet[k]);<br>}</blockquote>",
"<hr>",
"Fix the two indexing errors in the following function so all the numbers 1 through 5 are printed to the console."
],
"tests": [
{
"text": "Your code should set the initial condition of the loop so it starts at the first index.",
"testString": "assert(code.match(/i\\s*?=\\s*?0\\s*?;/g).length == 1, 'Your code should set the initial condition of the loop so it starts at the first index.');"
},
{
"text": "Your code should fix the initial condition of the loop so that the index starts at 0.",
"testString": "assert(!code.match(/i\\s?=\\s*?1\\s*?;/g), 'Your code should fix the initial condition of the loop so that the index starts at 0.');"
},
{
"text": "Your code should set the terminal condition of the loop so it stops at the last index.",
"testString": "assert(code.match(/i\\s*?<\\s*?len\\s*?;/g).length == 1, 'Your code should set the terminal condition of the loop so it stops at the last index.');"
},
{
"text": "Your code should fix the terminal condition of the loop so that it stops at 1 before the length.",
"testString": "assert(!code.match(/i\\s*?<=\\s*?len;/g), 'Your code should fix the terminal condition of the loop so that it stops at 1 before the length.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function countToFive() {",
" let firstFive = \"12345\";",
" let len = firstFive.length;",
" // Fix the line below",
" for (let i = 1; i <= len; i++) {",
" // Do not alter code below this line",
" console.log(firstFive[i]);",
" }",
"}",
"",
"countToFive();"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b86367417b2b2512b3c",
"title": "Use Caution When Reinitializing Variables Inside a Loop",
"description": [
"Sometimes it's necessary to save information, increment counters, or re-set variables within a loop. A potential issue is when variables either should be reinitialized, and aren't, or vice versa. This is particularly dangerous if you accidentally reset the variable being used for the terminal condition, causing an infinite loop.",
"Printing variable values with each cycle of your loop by using <code>console.log()</code> can uncover buggy behavior related to resetting, or failing to reset a variable.",
"<hr>",
"The following function is supposed to create a two-dimensional array with <code>m</code> rows and <code>n</code> columns of zeroes. Unfortunately, it's not producing the expected output because the <code>row</code> variable isn't being reinitialized (set back to an empty array) in the outer loop. Fix the code so it returns a correct 3x2 array of zeroes, which looks like <code>[[0, 0], [0, 0], [0, 0]]</code>."
],
"tests": [
{
"text": "Your code should set the <code>matrix</code> variable to an array holding 3 rows of 2 columns of zeroes each.",
"testString": "assert(JSON.stringify(matrix) == \"[[0,0],[0,0],[0,0]]\", 'Your code should set the <code>matrix</code> variable to an array holding 3 rows of 2 columns of zeroes each.');"
},
{
"text": "The <code>matrix</code> variable should have 3 rows.",
"testString": "assert(matrix.length == 3, 'The <code>matrix</code> variable should have 3 rows.');"
},
{
"text": "The <code>matrix</code> variable should have 2 columns in each row.",
"testString": "assert(matrix[0].length == 2 && matrix[1].length === 2 && matrix[2].length === 2, 'The <code>matrix</code> variable should have 2 columns in each row.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function zeroArray(m, n) {",
" // Creates a 2-D array with m rows and n columns of zeroes",
" let newArray = [];",
" let row = [];",
" for (let i = 0; i < m; i++) {",
" // Adds the m-th row into newArray",
" ",
" for (let j = 0; j < n; j++) {",
" // Pushes n zeroes into the current row to create the columns",
" row.push(0);",
" }",
" // Pushes the current row, which now has n zeroes in it, to the array",
" newArray.push(row);",
" }",
" return newArray;",
"}",
"",
"let matrix = zeroArray(3, 2);",
"console.log(matrix);"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7b86367417b2b2512b3d",
"title": "Prevent Infinite Loops with a Valid Terminal Condition",
"description": [
"The final topic is the dreaded infinite loop. Loops are great tools when you need your program to run a code block a certain number of times or until a condition is met, but they need a terminal condition that ends the looping. Infinite loops are likely to freeze or crash the browser, and cause general program execution mayhem, which no one wants.",
"There was an example of an infinite loop in the introduction to this section - it had no terminal condition to break out of the <code>while</code> loop inside <code>loopy()</code>. Do NOT call this function!",
"<blockquote>function loopy() {<br>&nbsp;&nbsp;while(true) {<br>&nbsp;&nbsp;&nbsp;&nbsp;console.log(\"Hello, world!\");<br>&nbsp;&nbsp;}<br>}</blockquote>",
"It's the programmer's job to ensure that the terminal condition, which tells the program when to break out of the loop code, is eventually reached. One error is incrementing or decrementing a counter variable in the wrong direction from the terminal condition. Another one is accidentally resetting a counter or index variable within the loop code, instead of incrementing or decrementing it.",
"<hr>",
"The <code>myFunc()</code> function contains an infinite loop because the terminal condition <code>i != 4</code> will never evaluate to <code>false</code> (and break the looping) - <code>i</code> will increment by 2 each pass, and jump right over 4 since <code>i</code> is odd to start. Fix the comparison operator in the terminal condition so the loop only runs for <code>i</code> less than or equal to 4."
],
"tests": [
{
"text": "Your code should change the comparison operator in the terminal condition (the middle part) of the <code>for</code> loop.",
"testString": "assert(code.match(/i\\s*?<=\\s*?4;/g).length == 1, 'Your code should change the comparison operator in the terminal condition (the middle part) of the <code>for</code> loop.');"
},
{
"text": "Your code should fix the comparison operator in the terminal condition of the loop.",
"testString": "assert(!code.match(/i\\s*?!=\\s*?4;/g), 'Your code should fix the comparison operator in the terminal condition of the loop.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 1,
"translations": {},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function myFunc() {",
" for (let i = 1; i != 4; i += 2) {",
" console.log(\"Still going!\");",
" }",
"}"
],
"head": [],
"tail": []
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,654 @@
{
"name": "JavaScript Algorithms and Data Structures Projects",
"order": 10,
"time": "50 hours",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Palindrome Checker",
"description": [
"Return <code>true</code> if the given string is a palindrome. Otherwise, return <code>false</code>.",
"A <dfn>palindrome</dfn> is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.",
"<strong>Note</strong><br>You'll need to remove <strong>all non-alphanumeric characters</strong> (punctuation, spaces and symbols) and turn everything into the same case (lower or upper case) in order to check for palindromes.",
"We'll pass strings with varying formats, such as <code>\"racecar\"</code>, <code>\"RaceCar\"</code>, and <code>\"race CAR\"</code> among others.",
"We'll also pass strings with special symbols, such as <code>\"2A3*3a2\"</code>, <code>\"2A3 3a2\"</code>, and <code>\"2_A3*3#A2\"</code>.",
"Remember to use <a href=\"http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"tests": [
{
"text": "<code>palindrome(\"eye\")</code> should return a boolean.",
"testString": "assert(typeof palindrome(\"eye\") === \"boolean\", '<code>palindrome(\"eye\")</code> should return a boolean.');"
},
{
"text": "<code>palindrome(\"eye\")</code> should return true.",
"testString": "assert(palindrome(\"eye\") === true, '<code>palindrome(\"eye\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"_eye\")</code> should return true.",
"testString": "assert(palindrome(\"_eye\") === true, '<code>palindrome(\"_eye\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"race car\")</code> should return true.",
"testString": "assert(palindrome(\"race car\") === true, '<code>palindrome(\"race car\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"not a palindrome\")</code> should return false.",
"testString": "assert(palindrome(\"not a palindrome\") === false, '<code>palindrome(\"not a palindrome\")</code> should return false.');"
},
{
"text": "<code>palindrome(\"A man, a plan, a canal. Panama\")</code> should return true.",
"testString": "assert(palindrome(\"A man, a plan, a canal. Panama\") === true, '<code>palindrome(\"A man, a plan, a canal. Panama\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"never odd or even\")</code> should return true.",
"testString": "assert(palindrome(\"never odd or even\") === true, '<code>palindrome(\"never odd or even\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"nope\")</code> should return false.",
"testString": "assert(palindrome(\"nope\") === false, '<code>palindrome(\"nope\")</code> should return false.');"
},
{
"text": "<code>palindrome(\"almostomla\")</code> should return false.",
"testString": "assert(palindrome(\"almostomla\") === false, '<code>palindrome(\"almostomla\")</code> should return false.');"
},
{
"text": "<code>palindrome(\"My age is 0, 0 si ega ym.\")</code> should return true.",
"testString": "assert(palindrome(\"My age is 0, 0 si ega ym.\") === true, '<code>palindrome(\"My age is 0, 0 si ega ym.\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"1 eye for of 1 eye.\")</code> should return false.",
"testString": "assert(palindrome(\"1 eye for of 1 eye.\") === false, '<code>palindrome(\"1 eye for of 1 eye.\")</code> should return false.');"
},
{
"text": "<code>palindrome(\"0_0 (: /-\\ :) 0-0\")</code> should return true.",
"testString": "assert(palindrome(\"0_0 (: /-\\ :) 0-0\") === true, '<code>palindrome(\"0_0 (: /-\\ :) 0-0\")</code> should return true.');"
},
{
"text": "<code>palindrome(\"five|\\_/|four\")</code> should return false.",
"testString": "assert(palindrome(\"five|\\_/|four\") === false, '<code>palindrome(\"five|\\_/|four\")</code> should return false.');"
}
],
"isRequired": true,
"solutions": [
"function palindrome(str) {\n var string = str.toLowerCase().split(/[^A-Za-z0-9]/gi).join('');\n var aux = string.split('');\n if (aux.join('') === aux.reverse().join('')){\n return true;\n }\n\n return false;\n}"
],
"MDNlinks": [
"String.prototype.replace()",
"String.prototype.toLowerCase()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Verifica si es palíndromo",
"description": [
"Crea una función que devuelva <code>true</code> si una cadena de texto dada es un palíndromo, y que devuelva <code>false</code> en caso contrario",
"Un palíndromo es una palabra u oración que se escribe de la misma forma en ambos sentidos, sin tomar en cuenta signos de puntuación, espacios y sin distinguir entre mayúsculas y minúsculas.",
"Tendrás que quitar los caracteres no alfanuméricos (signos de puntuación, espacioes y símbolos) y transformar las letras a minúsculas para poder verificar si el texto es palíndromo.",
"Te proveeremos textos en varios formatos, como \"racecar\", \"RaceCar\", and \"race CAR\" entre otros.",
"También vamos a pasar cadenas con símbolos especiales, tales como <code>\"2A3*3a2\"</code>, <code>\"2A3 3a2\"</code>, y <code>\"2_A3*3#A2\"</code>.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Procure por Palíndromos",
"description": [
"Retorne <code>true</code> se o texto fornecida é um palíndromo. Caso contrário, retorne <code>false</code>.",
"Um <dfn>palíndromo</dfn> é uma palavra ou sentença que é soletrada da mesma maneira tanto para a frente quanto para trás, ignorando pontuação, maiúsculas e minúsculas, e espaçamento.",
"<strong>Nota</strong><br>Você precisará remover <strong>todos caracteres não alfanuméricos</strong> (pontuação, espaços e símbolos) e transformar todas as letras em maiúsculas ou minúsculas para procurar por palíndromos.",
"Nós vamos passar textos de vários formatos, tais como <code>\"racecar\"</code>, <code>\"RaceCar\"</code> e <code>\"race CAR\"</code> entre outras.",
"Nós também vamos passar textos com símbolos especiais, tais como <code>\"2A3*3a2\"</code>, <code>\"2A3 3a2\"</code> e <code>\"2_A3*3#A2\"</code>.",
"Lembre-se de usar <a href=\"http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se você ficar travado. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function palindrome(str) {",
" // Good luck!",
" return true;",
"}",
"",
"",
"",
"palindrome(\"eye\");"
],
"head": [],
"tail": []
}
}
},
{
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter",
"description": [
"Convert the given number into a roman numeral.",
"All <a href=\"http://www.mathsisfun.com/roman-numerals.html\" target=\"_blank\">roman numerals</a> answers should be provided in upper-case.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"function convertToRoman(num) {\n var ref = [['M', 1000], ['CM', 900], ['D', 500], ['CD', 400], ['C', 100], ['XC', 90], ['L', 50], ['XL', 40], ['X', 10], ['IX', 9], ['V', 5], ['IV', 4], ['I', 1]];\n var res = [];\n ref.forEach(function(p) {\n while (num >= p[1]) {\n res.push(p[0]);\n num -= p[1];\n }\n });\n return res.join('');\n}"
],
"tests": [
{
"text": "<code>convertToRoman(2)</code> should return \"II\".",
"testString": "assert.deepEqual(convertToRoman(2), \"II\", '<code>convertToRoman(2)</code> should return \"II\".');"
},
{
"text": "<code>convertToRoman(3)</code> should return \"III\".",
"testString": "assert.deepEqual(convertToRoman(3), \"III\", '<code>convertToRoman(3)</code> should return \"III\".');"
},
{
"text": "<code>convertToRoman(4)</code> should return \"IV\".",
"testString": "assert.deepEqual(convertToRoman(4), \"IV\", '<code>convertToRoman(4)</code> should return \"IV\".');"
},
{
"text": "<code>convertToRoman(5)</code> should return \"V\".",
"testString": "assert.deepEqual(convertToRoman(5), \"V\", '<code>convertToRoman(5)</code> should return \"V\".');"
},
{
"text": "<code>convertToRoman(9)</code> should return \"IX\".",
"testString": "assert.deepEqual(convertToRoman(9), \"IX\", '<code>convertToRoman(9)</code> should return \"IX\".');"
},
{
"text": "<code>convertToRoman(12)</code> should return \"XII\".",
"testString": "assert.deepEqual(convertToRoman(12), \"XII\", '<code>convertToRoman(12)</code> should return \"XII\".');"
},
{
"text": "<code>convertToRoman(16)</code> should return \"XVI\".",
"testString": "assert.deepEqual(convertToRoman(16), \"XVI\", '<code>convertToRoman(16)</code> should return \"XVI\".');"
},
{
"text": "<code>convertToRoman(29)</code> should return \"XXIX\".",
"testString": "assert.deepEqual(convertToRoman(29), \"XXIX\", '<code>convertToRoman(29)</code> should return \"XXIX\".');"
},
{
"text": "<code>convertToRoman(44)</code> should return \"XLIV\".",
"testString": "assert.deepEqual(convertToRoman(44), \"XLIV\", '<code>convertToRoman(44)</code> should return \"XLIV\".');"
},
{
"text": "<code>convertToRoman(45)</code> should return \"XLV\"",
"testString": "assert.deepEqual(convertToRoman(45), \"XLV\", '<code>convertToRoman(45)</code> should return \"XLV\"');"
},
{
"text": "<code>convertToRoman(68)</code> should return \"LXVIII\"",
"testString": "assert.deepEqual(convertToRoman(68), \"LXVIII\", '<code>convertToRoman(68)</code> should return \"LXVIII\"');"
},
{
"text": "<code>convertToRoman(83)</code> should return \"LXXXIII\"",
"testString": "assert.deepEqual(convertToRoman(83), \"LXXXIII\", '<code>convertToRoman(83)</code> should return \"LXXXIII\"');"
},
{
"text": "<code>convertToRoman(97)</code> should return \"XCVII\"",
"testString": "assert.deepEqual(convertToRoman(97), \"XCVII\", '<code>convertToRoman(97)</code> should return \"XCVII\"');"
},
{
"text": "<code>convertToRoman(99)</code> should return \"XCIX\"",
"testString": "assert.deepEqual(convertToRoman(99), \"XCIX\", '<code>convertToRoman(99)</code> should return \"XCIX\"');"
},
{
"text": "<code>convertToRoman(400)</code> should return \"CD\"",
"testString": "assert.deepEqual(convertToRoman(400), \"CD\", '<code>convertToRoman(400)</code> should return \"CD\"');"
},
{
"text": "<code>convertToRoman(500)</code> should return \"D\"",
"testString": "assert.deepEqual(convertToRoman(500), \"D\", '<code>convertToRoman(500)</code> should return \"D\"');"
},
{
"text": "<code>convertToRoman(501)</code> should return \"DI\"",
"testString": "assert.deepEqual(convertToRoman(501), \"DI\", '<code>convertToRoman(501)</code> should return \"DI\"');"
},
{
"text": "<code>convertToRoman(649)</code> should return \"DCXLIX\"",
"testString": "assert.deepEqual(convertToRoman(649), \"DCXLIX\", '<code>convertToRoman(649)</code> should return \"DCXLIX\"');"
},
{
"text": "<code>convertToRoman(798)</code> should return \"DCCXCVIII\"",
"testString": "assert.deepEqual(convertToRoman(798), \"DCCXCVIII\", '<code>convertToRoman(798)</code> should return \"DCCXCVIII\"');"
},
{
"text": "<code>convertToRoman(891)</code> should return \"DCCCXCI\"",
"testString": "assert.deepEqual(convertToRoman(891), \"DCCCXCI\", '<code>convertToRoman(891)</code> should return \"DCCCXCI\"');"
},
{
"text": "<code>convertToRoman(1000)</code> should return \"M\"",
"testString": "assert.deepEqual(convertToRoman(1000), \"M\", '<code>convertToRoman(1000)</code> should return \"M\"');"
},
{
"text": "<code>convertToRoman(1004)</code> should return \"MIV\"",
"testString": "assert.deepEqual(convertToRoman(1004), \"MIV\", '<code>convertToRoman(1004)</code> should return \"MIV\"');"
},
{
"text": "<code>convertToRoman(1006)</code> should return \"MVI\"",
"testString": "assert.deepEqual(convertToRoman(1006), \"MVI\", '<code>convertToRoman(1006)</code> should return \"MVI\"');"
},
{
"text": "<code>convertToRoman(1023)</code> should return \"MXXIII\"",
"testString": "assert.deepEqual(convertToRoman(1023), \"MXXIII\", '<code>convertToRoman(1023)</code> should return \"MXXIII\"');"
},
{
"text": "<code>convertToRoman(2014)</code> should return \"MMXIV\"",
"testString": "assert.deepEqual(convertToRoman(2014), \"MMXIV\", '<code>convertToRoman(2014)</code> should return \"MMXIV\"');"
},
{
"text": "<code>convertToRoman(3999)</code> should return \"MMMCMXCIX\"",
"testString": "assert.deepEqual(convertToRoman(3999), \"MMMCMXCIX\", '<code>convertToRoman(3999)</code> should return \"MMMCMXCIX\"');"
}
],
"MDNlinks": [
"Roman Numerals",
"Array.prototype.splice()",
"Array.prototype.indexOf()",
"Array.prototype.join()"
],
"isRequired": true,
"challengeType": 5,
"translations": {
"es": {
"title": "Convertior de números romanos",
"description": [
"Convierte el número dado en numeral romano.",
"Todos los <a href=\"http://www.mathsisfun.com/roman-numerals.html\" target=\"_blank\">numerales romanos</a> en las respuestas deben estar en mayúsculas.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"fr": {
"title": "Convertir en chiffres romains",
"description": [
"Convertis le nombre donné en chiffres romains.",
"Tous les <a href=\"http://www.mathsisfun.com/roman-numerals.html\" target=\"_blank\">chiffres romains</a> doivent être en lettres capitales.",
"N'oublie pas d'utiliser <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Lire-Chercher-Demander</a> si tu es bloqué. Essaye de trouver un partenaire. Écris ton propre code."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function convertToRoman(num) {",
" return num;",
"}",
"",
"convertToRoman(36);"
],
"head": [],
"tail": []
}
}
},
{
"id": "56533eb9ac21ba0edf2244e2",
"title": "Caesars Cipher",
"description": [
"One of the simplest and most widely known <dfn>ciphers</dfn> is a <code>Caesar cipher</code>, also known as a <code>shift cipher</code>. In a <code>shift cipher</code> the meanings of the letters are shifted by some set amount.",
"A common modern use is the <a href=\"https://en.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a> cipher, where the values of the letters are shifted by 13 places. Thus 'A' &harr; 'N', 'B' &harr; 'O' and so on.",
"Write a function which takes a <a href=\"https://en.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a> encoded string as input and returns a decoded string.",
"All letters will be uppercase. Do not transform any non-alphabetic character (i.e. spaces, punctuation), but do pass them on.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"var lookup = {\n 'A': 'N','B': 'O','C': 'P','D': 'Q',\n 'E': 'R','F': 'S','G': 'T','H': 'U',\n 'I': 'V','J': 'W','K': 'X','L': 'Y',\n 'M': 'Z','N': 'A','O': 'B','P': 'C',\n 'Q': 'D','R': 'E','S': 'F','T': 'G',\n 'U': 'H','V': 'I','W': 'J','X': 'K',\n 'Y': 'L','Z': 'M' \n};\n\nfunction rot13(encodedStr) {\n var codeArr = encodedStr.split(\"\"); // String to Array\n var decodedArr = []; // Your Result goes here\n // Only change code below this line\n \n decodedArr = codeArr.map(function(letter) {\n if(lookup.hasOwnProperty(letter)) {\n letter = lookup[letter];\n }\n return letter;\n });\n\n // Only change code above this line\n return decodedArr.join(\"\"); // Array to String\n}"
],
"tests": [
{
"text": "<code>rot13(\"SERR PBQR PNZC\")</code> should decode to <code>FREE CODE CAMP</code>",
"testString": "assert(rot13(\"SERR PBQR PNZC\") === \"FREE CODE CAMP\", '<code>rot13(\"SERR PBQR PNZC\")</code> should decode to <code>FREE CODE CAMP</code>');"
},
{
"text": "<code>rot13(\"SERR CVMMN!\")</code> should decode to <code>FREE PIZZA!</code>",
"testString": "assert(rot13(\"SERR CVMMN!\") === \"FREE PIZZA!\", '<code>rot13(\"SERR CVMMN!\")</code> should decode to <code>FREE PIZZA!</code>');"
},
{
"text": "<code>rot13(\"SERR YBIR?\")</code> should decode to <code>FREE LOVE?</code>",
"testString": "assert(rot13(\"SERR YBIR?\") === \"FREE LOVE?\", '<code>rot13(\"SERR YBIR?\")</code> should decode to <code>FREE LOVE?</code>');"
},
{
"text": "<code>rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\")</code> should decode to <code>THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.</code>",
"testString": "assert(rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\") === \"THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.\", '<code>rot13(\"GUR DHVPX OEBJA SBK WHZCF BIRE GUR YNML QBT.\")</code> should decode to <code>THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG.</code>');"
}
],
"MDNlinks": [
"String.prototype.charCodeAt()",
"String.fromCharCode()"
],
"challengeType": 5,
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Cifrado César",
"description": [
"Uno de los <dfn>cifrados</dfn> más simples y ampliamente conocidos es el <code>cifrado César</code>, también llamado <code>cifrado por desplazamiento</code>. En un <code>cifrado por desplazamiento</code> los significados de las letras se desplazan por una cierta cantidad.",
"Un uso moderno común es el cifrado <a href=\"https://es.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a> , donde los valores de las letras se desplazan 13 espacios. De esta forma 'A' &harr; 'N', 'B' &harr; 'O' y así.",
"Crea una función que tome una cadena de texto cifrada en <a href=\"https://es.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a> como argumento y que devuelva la cadena de texto decodificada.",
"Todas las letras que se te pasen van a estar en mayúsculas. No transformes ningún caracter no-alfabético (por ejemplo: espacios, puntuación). Simplemente pásalos intactos.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"pt-br": {
"title": "Cifra de César",
"description": [
"Uma das mais simples e mais conhecidas <dfn>cifras</dfn> é a <code>cifra de César</code>, também conhecida como <code>cifra de troca</code>. Em uma <code>cifra de troca</code> os significados das letras são deslocados por um determinado valor.",
"Um uso moderno comum é a cifra <a href=\"https://en.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a>, aonde os valores das letras são deslocados por 13 lugares. Logo 'A' &harr; 'N', 'B' &harr; 'O' e assim por diante.",
"Escreva uma função que recebe um texto criptografado com <a href=\"https://en.wikipedia.org/wiki/ROT13\" target='_blank'>ROT13</a> como entrada e retorna o texto desencriptado.",
"Todas as letras serão maiúsculas. Não transforme nenhum caracter não alfanuméricos (como espaços, pontuação), mas passe-os adiante.",
"Lembre-se de usar <a href=\"http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514\" target=\"_blank\">Ler-Pesquisar-Perguntar</a> se você ficar travado. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function rot13(str) { // LBH QVQ VG!",
" ",
" return str;",
"}",
"",
"// Change the inputs below to test",
"rot13(\"SERR PBQR PNZC\");"
],
"head": [],
"tail": []
}
}
},
{
"id": "aff0395860f5d3034dc0bfc9",
"title": "Telephone Number Validator",
"description": [
"Return <code>true</code> if the passed string looks like a valid US phone number.",
"The user may fill out the form field any way they choose as long as it has the format of a valid US number. The following are examples of valid formats for US numbers (refer to the tests below for other variants):",
"<blockquote>555-555-5555<br>(555)555-5555<br>(555) 555-5555<br>555 555 5555<br>5555555555<br>1 555 555 5555</blockquote>",
"For this challenge you will be presented with a string such as <code>800-692-7753</code> or <code>8oo-six427676;laskdjf</code>. Your job is to validate or reject the US phone number based on any combination of the formats provided above. The area code is required. If the country code is provided, you must confirm that the country code is <code>1</code>. Return <code>true</code> if the string is a valid US phone number; otherwise return <code>false</code>.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"var re = /^([+]?1[\\s]?)?((?:[(](?:[2-9]1[02-9]|[2-9][02-8][0-9])[)][\\s]?)|(?:(?:[2-9]1[02-9]|[2-9][02-8][0-9])[\\s.-]?)){1}([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2}[\\s.-]?){1}([0-9]{4}){1}$/;\n\nfunction telephoneCheck(str) {\n return re.test(str);\n}\n\ntelephoneCheck(\"555-555-5555\");"
],
"tests": [
{
"text": "<code>telephoneCheck(\"555-555-5555\")</code> should return a boolean.",
"testString": "assert(typeof telephoneCheck(\"555-555-5555\") === \"boolean\", '<code>telephoneCheck(\"555-555-5555\")</code> should return a boolean.');"
},
{
"text": "<code>telephoneCheck(\"1 555-555-5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"1 555-555-5555\") === true, '<code>telephoneCheck(\"1 555-555-5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"1 (555) 555-5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"1 (555) 555-5555\") === true, '<code>telephoneCheck(\"1 (555) 555-5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"5555555555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"5555555555\") === true, '<code>telephoneCheck(\"5555555555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"555-555-5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"555-555-5555\") === true, '<code>telephoneCheck(\"555-555-5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"(555)555-5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"(555)555-5555\") === true, '<code>telephoneCheck(\"(555)555-5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"1(555)555-5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"1(555)555-5555\") === true, '<code>telephoneCheck(\"1(555)555-5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"555-5555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"555-5555\") === false, '<code>telephoneCheck(\"555-5555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"5555555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"5555555\") === false, '<code>telephoneCheck(\"5555555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"1 555)555-5555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"1 555)555-5555\") === false, '<code>telephoneCheck(\"1 555)555-5555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"1 555 555 5555\")</code> should return true.",
"testString": "assert(telephoneCheck(\"1 555 555 5555\") === true, '<code>telephoneCheck(\"1 555 555 5555\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"1 456 789 4444\")</code> should return true.",
"testString": "assert(telephoneCheck(\"1 456 789 4444\") === true, '<code>telephoneCheck(\"1 456 789 4444\")</code> should return true.');"
},
{
"text": "<code>telephoneCheck(\"123**&!!asdf#\")</code> should return false.",
"testString": "assert(telephoneCheck(\"123**&!!asdf#\") === false, '<code>telephoneCheck(\"123**&!!asdf#\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"55555555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"55555555\") === false, '<code>telephoneCheck(\"55555555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"(6054756961)\")</code> should return false",
"testString": "assert(telephoneCheck(\"(6054756961)\") === false, '<code>telephoneCheck(\"(6054756961)\")</code> should return false');"
},
{
"text": "<code>telephoneCheck(\"2 (757) 622-7382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"2 (757) 622-7382\") === false, '<code>telephoneCheck(\"2 (757) 622-7382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"0 (757) 622-7382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"0 (757) 622-7382\") === false, '<code>telephoneCheck(\"0 (757) 622-7382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"-1 (757) 622-7382\")</code> should return false",
"testString": "assert(telephoneCheck(\"-1 (757) 622-7382\") === false, '<code>telephoneCheck(\"-1 (757) 622-7382\")</code> should return false');"
},
{
"text": "<code>telephoneCheck(\"2 757 622-7382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"2 757 622-7382\") === false, '<code>telephoneCheck(\"2 757 622-7382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"10 (757) 622-7382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"10 (757) 622-7382\") === false, '<code>telephoneCheck(\"10 (757) 622-7382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"27576227382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"27576227382\") === false, '<code>telephoneCheck(\"27576227382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"(275)76227382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"(275)76227382\") === false, '<code>telephoneCheck(\"(275)76227382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"2(757)6227382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"2(757)6227382\") === false, '<code>telephoneCheck(\"2(757)6227382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"2(757)622-7382\")</code> should return false.",
"testString": "assert(telephoneCheck(\"2(757)622-7382\") === false, '<code>telephoneCheck(\"2(757)622-7382\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"555)-555-5555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"555)-555-5555\") === false, '<code>telephoneCheck(\"555)-555-5555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"(555-555-5555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"(555-555-5555\") === false, '<code>telephoneCheck(\"(555-555-5555\")</code> should return false.');"
},
{
"text": "<code>telephoneCheck(\"(555)5(55?)-5555\")</code> should return false.",
"testString": "assert(telephoneCheck(\"(555)5(55?)-5555\") === false, '<code>telephoneCheck(\"(555)5(55?)-5555\")</code> should return false.');"
}
],
"MDNlinks": [
"RegExp"
],
"challengeType": 5,
"isRequired": true,
"translations": {
"es": {
"title": "Valida Números Telefónicos de los EEUU",
"description": [
"Haz que la función devuelva true (verdadero) si el texto introducido parece un número válido en los EEUU.",
"El usuario debe llenar el campo del formulario de la forma que desee siempre y cuando tenga el formato de un número válido en los EEUU. Los números mostrados a continuación tienen formatos válidos en los EEUU:",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"Para esta prueba se te presentará una cadena de texto como por ejemplo: <code>800-692-7753</code> o <code>8oo-six427676;laskdjf</code>. Tu trabajo consiste en validar o rechazar el número telefónico tomando como base cualquier combinación de los formatos anteriormente presentados. El código de área es requrido. Si el código de país es provisto, debes confirmar que este es <code>1</code>. La función debe devolver true si la cadena de texto es un número telefónico válido en los EEUU; de lo contrario, debe devolver false.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Verifica i numeri telefonici degli Stati Uniti",
"description": [
"Ritorna <code>true</code> se la stringa passata come argomento è un numero valido negli Stati Uniti.",
"L'utente può digitare qualunque stringa nel campo di inserimento, purchè sia un numero di telefono valido negli Stati Uniti. Qui sotto alcuni esempi di numeri di telefono validi negli Stati Uniti (fai riferimento ai test per le altre varianti):",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"In questo problema ti saranno presentate delle stringe come <code>800-692-7753</code> o <code>8oo-six427676;laskdjf</code>. Il tuo obiettivo è di validare o rigettare il numero di telefono basato su una qualunque combinazione dei formati specificati sopra. Il prefisso di zona è obbligatorio. Se il prefisso nazionale è presente, devi confermare che corrisponda a <code>1</code>. Ritorna <code>true</code> se la stringa è un numero di telefono valido negli Stati Uniti; altrimenti ritorna <code>false</code>.",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Valida números telefônicos dos EUA",
"description": [
"Retorna <code>true</code> se a string passada é um número telefônico válido nos EUA.",
"O usuário pode preencher o campo de qualquer maneira com tanto que seja um número válido nos EUA. Os seguintes exemplos são formatos válidos para números de telefone nos EUA (baseie-se nos testes abaixo para outras variações):",
"<blockquote>555-555-5555\n(555)555-5555\n(555) 555-5555\n555 555 5555\n5555555555\n1 555 555 5555</blockquote>",
"Para esse desafio será dado a você uma string como <code>800-692-7753</code> ou <code>8oo-six427676;laskdjf</code>. Seu trabalho é validar ou rejeitar o número de telefone dos EUA baseado nos exmplos de formatos fornecidos acima. O código de área é obrigatório. Se o código do país for fornecido, você deve confirmar que o código do país é <code>1</code>. Retorne <code>true</code> se a string é um número válido nos EUA; caso contrário retorne <code>false</code>.",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function telephoneCheck(str) {",
" // Good luck!",
" return true;",
"}",
"",
"telephoneCheck(\"555-555-5555\");"
],
"head": [],
"tail": []
}
}
},
{
"id": "aa2e6f85cab2ab736c9a9b24",
"title": "Cash Register",
"description": [
"Design a cash register drawer function <code>checkCashRegister()</code> that accepts purchase price as the first argument (<code>price</code>), payment as the second argument (<code>cash</code>), and cash-in-drawer (<code>cid</code>) as the third argument.",
"<code>cid</code> is a 2D array listing available currency.",
"The <code>checkCashRegister()</code> function should always return an object with a <code>status</code> key and a <code>change</code> key.",
"Return <code>{status: \"INSUFFICIENT_FUNDS\", change: []}</code> if cash-in-drawer is less than the change due, or if you cannot return the exact change.",
"Return <code>{status: \"CLOSED\", change: [...]}</code> with cash-in-drawer as the value for the key <code>change</code> if it is equal to the change due.",
"Otherwise, return <code>{status: \"OPEN\", change: [...]}</code>, with the change due in coins and bills, sorted in highest to lowest order, as the value of the <code>change</code> key.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code.",
"<table class='table table-striped'><tr><th>Currency Unit</th><th>Amount</th></tr><tr><td>Penny</td><td>$0.01 (PENNY)</td></tr><tr><td>Nickel</td><td>$0.05 (NICKEL)</td></tr><tr><td>Dime</td><td>$0.1 (DIME)</td></tr><tr><td>Quarter</td><td>$0.25 (QUARTER)</td></tr><tr><td>Dollar</td><td>$1 (DOLLAR)</td></tr><tr><td>Five Dollars</td><td>$5 (FIVE)</td></tr><tr><td>Ten Dollars</td><td>$10 (TEN)</td></tr><tr><td>Twenty Dollars</td><td>$20 (TWENTY)</td></tr><tr><td>One-hundred Dollars</td><td>$100 (ONE HUNDRED)</td></tr></table>"
],
"solutions": [
"var denom = [\n\t{ name: 'ONE HUNDRED', val: 100},\n\t{ name: 'TWENTY', val: 20},\n\t{ name: 'TEN', val: 10},\n\t{ name: 'FIVE', val: 5},\n\t{ name: 'ONE', val: 1},\n\t{ name: 'QUARTER', val: 0.25},\n\t{ name: 'DIME', val: 0.1},\n\t{ name: 'NICKEL', val: 0.05},\n\t{ name: 'PENNY', val: 0.01}\n];\n\nfunction checkCashRegister(price, cash, cid) {\n var output = {status: null, change: []};\n var change = cash - price;\n var register = cid.reduce(function(acc, curr) {\n acc.total += curr[1];\n acc[curr[0]] = curr[1];\n return acc;\n }, {total: 0});\n if(register.total === change) {\n output.status = 'CLOSED';\n output.change = cid;\n return output;\n }\n if(register.total < change) {\n output.status = 'INSUFFICIENT_FUNDS';\n return output;\n }\n var change_arr = denom.reduce(function(acc, curr) {\n var value = 0;\n while(register[curr.name] > 0 && change >= curr.val) {\n change -= curr.val;\n register[curr.name] -= curr.val;\n value += curr.val;\n change = Math.round(change * 100) / 100;\n }\n if(value > 0) {\n acc.push([ curr.name, value ]);\n }\n return acc;\n }, []);\n if(change_arr.length < 1 || change > 0) {\n output.status = 'INSUFFICIENT_FUNDS';\n return output;\n }\n output.status = 'OPEN';\n output.change = change_arr;\n return output;\n}"
],
"tests": [
{
"text": "<code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return an object.",
"testString": "assert.deepEqual(Object.prototype.toString.call(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])), '[object Object]', '<code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return an object.');"
},
{
"text": "<code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>{status: \"OPEN\", change: [[\"QUARTER\", 0.5]]}</code>.",
"testString": "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), {status: \"OPEN\", change: [[\"QUARTER\", 0.5]]}, '<code>checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>{status: \"OPEN\", change: [[\"QUARTER\", 0.5]]}</code>.');"
},
{
"text": "<code>checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>{status: \"OPEN\", change: [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]]}</code>.",
"testString": "assert.deepEqual(checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]), {status: \"OPEN\", change: [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]]}, '<code>checkCashRegister(3.26, 100, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]])</code> should return <code>{status: \"OPEN\", change: [[\"TWENTY\", 60], [\"TEN\", 20], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.5], [\"DIME\", 0.2], [\"PENNY\", 0.04]]}</code>.');"
},
{
"text": "<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"INSUFFICIENT_FUNDS\", change: []}</code>.",
"testString": "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), {status: \"INSUFFICIENT_FUNDS\", change: []}, '<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"INSUFFICIENT_FUNDS\", change: []}</code>.');"
},
{
"text": "<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"INSUFFICIENT_FUNDS\", change: []}</code>.",
"testString": "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), {status: \"INSUFFICIENT_FUNDS\", change: []}, '<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"INSUFFICIENT_FUNDS\", change: []}</code>.');"
},
{
"text": "<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"CLOSED\", change: [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]}</code>.",
"testString": "assert.deepEqual(checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), {status: \"CLOSED\", change: [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]}, '<code>checkCashRegister(19.5, 20, [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return <code>{status: \"CLOSED\", change: [[\"PENNY\", 0.5], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]}</code>.');"
}
],
"isRequired": true,
"MDNlinks": [
"Global Object",
"Floating Point Guide"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Cambio Exacto",
"description": [
"Crea una función que simule una caja registradora que acepte el precio de compra como el primer argumento, la cantidad recibida como el segundo argumento, y la cantidad de dinero disponible en la registradora (cid) como tercer argumento",
"cid es un arreglo bidimensional que lista la cantidad de dinero disponible",
"La función debe devolver la cadena de texto \"Insufficient Funds\" si el cid es menor al cambio requerido. También debe devolver \"Closed\" si el cid es igual al cambio",
"De no ser el caso, devuelve el cambio en monedas y billetes, ordenados de mayor a menor denominación.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Cambio Esatto",
"description": [
"Scrivi una funzione che simuli un registro di cassa chiamata <code>checkCashRegister()</code> che accetti il prezzo degli articoli come primo argomento (<code>price</code>), la somma pagata (<code>cash</code>), e la somma disponibile nel registratore di cassa (<code>cid</code>) come terzo argomento.",
"<code>cid</code> è un array a due dimensioni che contiene la quantità di monete e banconote disponibili.",
"Ritorna la stringa <code>\"Insufficient Funds\"</code> se la quantità di denaro disponibile nel registratore di cassa non è abbastanza per restituire il resto. Ritorna la stringa <code>\"Closed\"</code> se il denaro disponibile è esattamente uguale al resto.",
"Altrimenti, ritorna il resto in monete e banconote, ordinate da quelle con valore maggiore a quelle con valore minore.",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Troco Exato",
"description": [
"Crie uma função que simula uma caixa registradora chamada <code>checkCashRegister()</code> e aceita o valor da compra como primeiro argumento (<code>price</code>), pagamento como segundo argumento (<code>cash</code>), e o dinheiro na caixa registradora (<code>cid</code>) como terceiro argumento.",
"<code>cid</code> é uma matriz bidimensional que lista o dinheiro disponível.",
"Retorne a string <code>\"Insufficient Funds\"</code> se o dinheiro na caixa registradora é menor do que o troco ou se não é possível retornar o troco exato. Retorne a string <code>\"Closed\"</code> se o dinheiro na caixa é igual ao troco.",
"Case cotrário, retorne o troco em moedas e notas, ordenado do maior para menor.",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código.",
"<table class='table table-striped'><tr><th>Currency Unit</th><th>Amount</th></tr><tr><td>Penny</td><td>$0.01 (PENNY)</td></tr><tr><td>Nickel</td><td>$0.05 (NICKEL)</td></tr><tr><td>Dime</td><td>$0.1 (DIME)</td></tr><tr><td>Quarter</td><td>$0.25 (QUARTER)</td></tr><tr><td>Dollar</td><td>$1 (DOLLAR)</td></tr><tr><td>Five Dollars</td><td>$5 (FIVE)</td></tr><tr><td>Ten Dollars</td><td>$10 (TEN)</td></tr><tr><td>Twenty Dollars</td><td>$20 (TWENTY)</td></tr><tr><td>One-hundred Dollars</td><td>$100 (ONE HUNDRED)</td></tr></table>"
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function checkCashRegister(price, cash, cid) {",
" var change;",
" // Here is your change, ma'am.",
" return change;",
"}",
"",
"// Example cash-in-drawer array:",
"// [[\"PENNY\", 1.01],",
"// [\"NICKEL\", 2.05],",
"// [\"DIME\", 3.1],",
"// [\"QUARTER\", 4.25],",
"// [\"ONE\", 90],",
"// [\"FIVE\", 55],",
"// [\"TEN\", 20],",
"// [\"TWENTY\", 60],",
"// [\"ONE HUNDRED\", 100]]",
"",
"checkCashRegister(19.5, 20, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.1], [\"QUARTER\", 4.25], [\"ONE\", 90], [\"FIVE\", 55], [\"TEN\", 20], [\"TWENTY\", 60], [\"ONE HUNDRED\", 100]]);"
],
"head": [],
"tail": []
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,193 @@
{
"name": "Front End Libraries Projects",
"order": 8,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/qRZeGZ' target='_blank'>https://codepen.io/freeCodeCamp/full/qRZeGZ</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I can see a wrapper element with a corresponding <code>id=\"quote-box\"</code>.",
"<strong>User Story #2:</strong> Within <code>#quote-box</code>, I can see an element with a corresponding <code>id=\"text\"</code>.",
"<strong>User Story #3:</strong> Within <code>#quote-box</code>, I can see an element with a corresponding <code>id=\"author\"</code>.",
"<strong>User Story #4:</strong> Within <code>#quote-box</code>, I can see a clickable element with a corresponding <code>id=\"new-quote\"</code>.",
"<strong>User Story #5:</strong> Within <code>#quote-box</code>, I can see a clickable <codea</code> element with a corresponding <code>id=\"tweet-quote\"</code>.",
"<strong>User Story #6:</strong> On first load, my quote machine displays a random quote in the element with <code>id=\"text\"</code>.",
"<strong>User Story #7:</strong> On first load, my quote machine displays the random quote's author in the element with <code>id=\"author\"</code>.",
"<strong>User Story #8:</strong> When the <code>#new-quote</code> button is clicked, my quote machine should fetch a new quote and display it in the <code>#text</code> element.",
"<strong>User Story #9:</strong> My quote machine should fetch the new quote's author when the <code>#new-quote</code> button is clicked and display it in the <code>#author</code> element.",
"<strong>User Story #10:</strong> I can tweet the current quote by clicking on the <code>#tweet-quote</code> <code>a</code> element. This <code>a</code> element should include the <code>\"twitter.com/intent/tweet\"</code> path in it's <code>href</code> attribute to tweet the current quote.",
"<strong>User Story #11:</strong> The <code>#quote-box</code> wrapper element should be horizontally centered. Please run tests with browser's zoom level at 100% and page maximized.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea una máquina de frases aleatorias"
},
"ru": {
"title": "Создайте генератор случайных цитат"
}
}
},
{
"id": "bd7157d8c242eddfaeb5bd13",
"title": "Build a Markdown Previewer",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/GrZVVO' target='_blank'>https://codepen.io/freeCodeCamp/full/GrZVVO</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I can see a <code>textarea</code> element with a corresponding <code>id=\"editor\"</code>.",
"<strong>User Story #2:</strong> I can see an element with a corresponding <code>id=\"preview\"</code>.",
"<strong>User Story #3:</strong> When I enter text into the <code>#editor</code> element, the <code>#preview</code> element is updated as I type to display the content of the textarea.",
"<strong>User Story #4:</strong> When I enter GitHub flavored markdown into the <code>#editor</code> element, the text is rendered as HTML in the <code>#preview</code> element as I type (HINT: You don't need to parse Markdown yourself - you can import the Marked library for this: <a href='https://cdnjs.com/libraries/marked' target='_blank'>https://cdnjs.com/libraries/marked</a>).",
"<strong>User Story #5:</strong> When my markdown previewer first loads, the default text in the <code>#editor</code> field should contain valid markdown that represents at least one of each of the following elements: a header (H1 size), a sub header (H2 size), a link, inline code, a code block, a list item, a blockquote, an image, and bolded text.",
"<strong>User Story #6:</strong> When my markdown previewer first loads, the default markdown in the <code>#editor</code> field should be rendered as HTML in the <code>#preview</code> element.",
"<strong>Optional Bonus (you do not need to make this test pass):</strong> When I click a link rendered by my markdown previewer, the link is opened up in a new tab (HINT: read the Marked.js docs for this one!).",
"<strong>Optional Bonus (you do not need to make this test pass):</strong> My markdown previewer interprets carriage returns and renders them as <code>br</code> (line break) elements.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "January 10, 2017",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea una caja de recetas"
},
"ru": {
"title": "Создайте хранилище рецептов"
}
}
},
{
"id": "587d7dbc367417b2b2512bae",
"title": "Build a Drum Machine",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/MJyNMd' target='_blank'>https://codepen.io/freeCodeCamp/full/MJyNMd</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I should be able to see an outer container with a corresponding <code>id=\"drum-machine\"</code> that contains all other elements.",
"<strong>User Story #2:</strong> Within <code>#drum-machine</code> I can see an element with a corresponding <code>id=\"display\"</code>.",
"<strong>User Story #3:</strong> Within <code>#drum-machine</code> I can see 9 clickable drum pad elements, each with a class name of <code>drum-pad</code>, a unique id that describes the audio clip the drum pad will be set up to trigger, and an inner text that corresponds to one of the following keys on the keyboard: Q, W, E, A, S, D, Z, X, C. The drum pads MUST be in this order.",
"<strong>User Story #4:</strong> Within each <code>.drum-pad</code>, there should be an HTML5 <code>audio</code> element which has a <code>src</code> attribute pointing to an audio clip, a class name of <code>clip</code>, and an id corresponding to the inner text of its parent <code>.drum-pad</code> (e.g. <code>id=\"Q\"</code>, <code>id=\"W\"</code>, <code>id=\"E\"</code> etc.).",
"<strong>User Story #5:</strong> When I click on a <code>.drum-pad</code> element, the audio clip contained in its child <code>audio</code> element should be triggered.",
"<strong>User Story #6:</strong> When I press the trigger key associated with each <code>.drum-pad</code>, the audio clip contained in its child <code>audio</code> element should be triggered (e.g. pressing the Q key should trigger the drum pad which contains the string \"Q\", pressing the W key should trigger the drum pad which contains the string \"W\", etc.).",
"<strong>User Story #7:</strong> When a <code>.drum-pad</code> is triggered, a string describing the associated audio clip is displayed as the inner text of the <code>#display</code> element (each string must be unique).",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"releasedOn": "February 17, 2017",
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un Juego de la vida"
},
"ru": {
"title": "Создайте игру \"Жизнь\""
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/wgGVVX' target='_blank'>https://codepen.io/freeCodeCamp/full/wgGVVX</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> My calculator should contain a clickable element containing an <code>=</code> (equal sign) with a corresponding <code>id=\"equals\"</code>.",
"<strong>User Story #2:</strong> My calculator should contain 10 clickable elements containing one number each from 0-9, with the following corresponding IDs: <code>id=\"zero\"</code>, <code>id=\"one\"</code>, <code>id=\"two\"</code>, <code>id=\"three\"</code>, <code>id=\"four\"</code>, <code>id=\"five\"</code>, <code>id=\"six\"</code>, <code>id=\"seven\"</code>, <code>id=\"eight\"</code>, and <code>id=\"nine\"</code>.",
"<strong>User Story #3:</strong> My calculator should contain 4 clickable elements each containing one of the 4 primary mathematical operators with the following corresponding IDs: <code>id=\"add\"</code>, <code>id=\"subtract\"</code>, <code>id=\"multiply\"</code>, <code>id=\"divide\"</code>.",
"<strong>User Story #4:</strong> My calculator should contain a clickable element containing a <code>.</code> (decimal point) symbol with a corresponding <code>id=\"decimal\"</code>.",
"<strong>User Story #5:</strong> My calculator should contain a clickable element with an <code>id=\"clear\"</code>.",
"<strong>User Story #6:</strong> My calculator should contain an element to display values with a corresponding <code>id=\"display\"</code>.",
"<strong>User Story #7:</strong> At any time, pressing the clear button clears the input and output values, and returns the calculator to its initialized state; 0 should be shown in the element with the id of <code>display</code>.",
"<strong>User Story #8:</strong> As I input numbers, I should be able to see my input in the element with the id of <code>display</code>.",
"<strong>User Story #9:</strong> In any order, I should be able to add, subtract, multiply and divide a chain of numbers of any length, and when I hit <code>=</code>, the correct result should be shown in the element with the id of <code>display</code>.",
"<strong>User Story #10:</strong> When inputting numbers, my calculator should not allow a number to begin with multiple zeros.",
"<strong>User Story #11:</strong> When the decimal element is clicked, a <code>.</code> should append to the currently displayed value; two <code>.</code> in one number should not be accepted.",
"<strong>User Story #12:</strong> I should be able to perform any operation (+, -, *, /) on numbers containing decimal points.",
"<strong>User Story #13:</strong> If 2 or more operators are entered consecutively, the operation performed should be the last operator entered.",
"<strong>User Story #14:</strong> Pressing an operator immediately following <code>=</code> should start a new calculation that operates on the result of the previous evaluation.",
"<strong>User Story #15:</strong> My calculator should have several decimal places of precision when it comes to rounding (note that there is no exact standard, but you should be able to handle calculations like <code>2 / 7</code> with reasonable precision to at least 4 decimal places).",
"<strong>Note On Calculator Logic:</strong> It should be noted that there are two main schools of thought on calculator input logic: <dfn>immediate execution logic</dfn> and <dfn>formula logic</dfn>. Our example utilizes formula logic and observes order of operation precedence, immediate execution does not. Either is acceptable, but please note that depending on which you choose, your calculator may yield different results than ours for certain equations (see below example). As long as your math can be verified by another production calculator, please do not consider this a bug.",
"<strong>EXAMPLE:</strong> <code>3 + 5 x 6 - 2 / 4 =</code><br><ul><li><strong>Immediate Execution Logic:</strong> <code>11.5</code></li><li><strong>Formula/Expression Logic:</strong> <code>32.5</code></li></ul>",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"challengeType": 3,
"isRequired": true,
"translations": {
"es": {
"title": "Crea una calculadora JavaScript"
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/XpKrrW' target='_blank'>https://codepen.io/freeCodeCamp/full/XpKrrW</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use any mix of HTML, JavaScript, CSS, Bootstrap, SASS, React, Redux, and jQuery to complete this project. You should use a frontend framework (like React for example) because this section is about learning frontend frameworks. Additional technologies not listed above are not recommended and using them is at your own risk. We are looking at supporting other frontend frameworks like Angular and Vue, but they are not currently supported. We will accept and try to fix all issue reports that use the suggested technology stack for this project. Happy coding!",
"<strong>User Story #1:</strong> I can see an element with <code>id=\"break-label\"</code> that contains a string (e.g. \"Break Length\").",
"<strong>User Story #2:</strong> I can see an element with <code>id=\"session-label\"</code> that contains a string (e.g. \"Session Length\").",
"<strong>User Story #3:</strong> I can see two clickable elements with corresponding IDs: <code>id=\"break-decrement\"</code> and <code>id=\"session-decrement\"</code>.",
"<strong>User Story #4:</strong> I can see two clickable elements with corresponding IDs: <code>id=\"break-increment\"</code> and <code>id=\"session-increment\"</code>.",
"<strong>User Story #5:</strong> I can see an element with a corresponding <code>id=\"break-length\"</code>, which by default (on load) displays a value of 5.",
"<strong>User Story #6:</strong> I can see an element with a corresponding <code>id=\"session-length\"</code>, which by default displays a value of 25.",
"<strong>User Story #7:</strong> I can see an element with a corresponding <code>id=\"timer-label\"</code>, that contains a string indicating a session is initialized (e.g. \"Session\").",
"<strong>User Story #8:</strong> I can see an element with corresponding <code>id=\"time-left\"</code>. NOTE: Paused or running, the value in this field should always be displayed in <code>mm:ss</code> format (i.e. 25:00).",
"<strong>User Story #9:</strong> I can see a clickable element with a corresponding <code>id=\"start_stop\"</code>.",
"<strong>User Story #10:</strong> I can see a clickable element with a corresponding <code>id=\"reset\"</code>.",
"<strong>User Story #11:</strong> When I click the element with the id of <code>reset</code>, any running timer should be stopped, the value within <code>id=\"break-length\"</code> should return to <code>5</code>, the value within <code>id=\"session-length\"</code> should return to 25, and the element with <code>id=\"time-left\"</code> should reset to it's default state.",
"<strong>User Story #12:</strong> When I click the element with the id of <code>break-decrement</code>, the value within <code>id=\"break-length\"</code> decrements by a value of 1, and I can see the updated value.",
"<strong>User Story #13:</strong> When I click the element with the id of <code>break-increment</code>, the value within <code>id=\"break-length\"</code> increments by a value of 1, and I can see the updated value.",
"<strong>User Story #14:</strong> When I click the element with the id of <code>session-decrement</code>, the value within <code>id=\"session-length\"</code> decrements by a value of 1, and I can see the updated value.",
"<strong>User Story #15:</strong> When I click the element with the id of <code>session-increment</code>, the value within <code>id=\"session-length\"</code> increments by a value of 1, and I can see the updated value.",
"<strong>User Story #16:</strong> I should not be able to set a session or break length to <= 0.",
"<strong>User Story #17:</strong> I should not be able to set a session or break length to > 60.",
"<strong>User Story #18:</strong> When I first click the element with <code>id=\"start_stop\"</code>, the timer should begin running from the value currently displayed in <code>id=\"session-length\"</code>, even if the value has been incremented or decremented from the original value of 25.",
"<strong>User Story #19:</strong> If the timer is running, the element with the id of <code>time-left</code> should display the remaining time in <code>mm:ss</code> format (decrementing by a value of 1 and updating the display every 1000ms).",
"<strong>User Story #20:</strong> If the timer is running and I click the element with <code>id=\"start_stop\"</code>, the countdown should pause.",
"<strong>User Story #21:</strong> If the timer is paused and I click the element with <code>id=\"start_stop\"</code>, the countdown should resume running from the point at which it was paused.",
"<strong>User Story #22:</strong> When a session countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of <code>timer-label</code> should display a string indicating a break has begun.",
"<strong>User Story #23:</strong> When a session countdown reaches zero (NOTE: timer MUST reach 00:00), a new break countdown should begin, counting down from the value currently displayed in the <code>id=\"break-length\"</code> element.",
"<strong>User Story #24:</strong> When a break countdown reaches zero (NOTE: timer MUST reach 00:00), and a new countdown begins, the element with the id of <code>timer-label</code> should display a string indicating a session has begun.",
"<strong>User Story #25:</strong> When a break countdown reaches zero (NOTE: timer MUST reach 00:00), a new session countdown should begin, counting down from the value currently displayed in the <code>id=\"session-length\"</code> element.",
"<strong>User Story #26:</strong> When a countdown reaches zero (NOTE: timer MUST reach 00:00), a sound indicating that time is up should play. This should utilize an HTML5 <code>audio</code> tag and have a corresponding <code>id=\"beep\"</code>.",
"<strong>User Story #27:</strong> The audio element with <code>id=\"beep\"</code> must be 1 second or longer.",
"<strong>User Story #28:</strong> The audio element with id of <code>beep</code> must stop playing and be rewound to the beginning when the element with the id of <code>reset</code> is clicked.",
"You can build your project by forking <a href='http://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un reloj pomodoro"
},
"ru": {
"title": "Создайте таймер Pomodoro"
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,997 @@
{
"name": "React and Redux",
"order": 7,
"time": "5 hours",
"helpRoom": "Help",
"required": [
{
"src": "https://unpkg.com/react@16.4.0/umd/react.production.min.js"
},
{
"src":
"https://unpkg.com/react-dom@16.4.0/umd/react-dom.production.min.js"
},
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/redux/3.7.2/redux.min.js"
},
{
"src":
"https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.7/react-redux.min.js"
}
],
"template": "<body><div id='root'></div>${ source || '' }</body>",
"challenges": [
{
"id": "5a24c314108439a4d4036141",
"title": "Getting Started with React Redux",
"releasedOn": "December 25, 2017",
"description": [
"This series of challenges introduces how to use Redux with React. First, here's a review of some of the key principles of each technology. React is a view library that you provide with data, then it renders the view in an efficient, predictable way. Redux is a state management framework that you can use to simplify the management of your application's state. Typically, in a React Redux app, you create a single Redux store that manages the state of your entire app. Your React components subscribe to only the pieces of data in the store that are relevant to their role. Then, you dispatch actions directly from React components, which then trigger store updates.",
"Although React components can manage their own state locally, when you have a complex app, it's generally better to keep the app state in a single location with Redux. There are exceptions when individual components may have local state specific only to them. Finally, because Redux is not designed to work with React out of the box, you need to use the <code>react-redux</code> package. It provides a way for you to pass Redux <code>state</code> and <code>dispatch</code> to your React components as <code>props</code>.",
"Over the next few challenges, first, you'll create a simple React component which allows you to input new text messages. These are added to an array that's displayed in the view. This should be a nice review of what you learned in the React lessons. Next, you'll create a Redux store and actions that manage the state of the messages array. Finally, you'll use <code>react-redux</code> to connect the Redux store with your component, thereby extracting the local state into the Redux store.",
"<hr>",
"Start with a <code>DisplayMessages</code> component. Add a constructor to this component and initialize it with a state that has two properties: <code>input</code>, that's set to an empty string, and <code>messages</code>, that's set to an empty array."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"class DisplayMessages extends React.Component {",
" // change code below this line",
"",
" // change code above this line",
" render() {",
" return <div />",
" }",
"};"
],
"tail": [
"ReactDOM.render(<DisplayMessages />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text":
"The <code>DisplayMessages</code> component should render an empty <code>div</code> element.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); return mockedComponent.find('div').text() === '' })(), 'The <code>DisplayMessages</code> component should render an empty <code>div</code> element.');"
},
{
"text":
"The <code>DisplayMessages</code> constructor should be called properly with <code>super</code>, passing in <code>props</code>.",
"testString":
"getUserInput => assert((function() { const noWhiteSpace = getUserInput('index').replace(/\\s/g,''); return noWhiteSpace.includes('constructor(props)') && noWhiteSpace.includes('super(props'); })(), 'The <code>DisplayMessages</code> constructor should be called properly with <code>super</code>, passing in <code>props</code>.');"
},
{
"text":
"The <code>DisplayMessages</code> component should have an initial state equal to <code>{input: \"\", messages: []}</code>.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return typeof initialState === 'object' && initialState.input === '' && Array.isArray(initialState.messages) && initialState.messages.length === 0; })(), 'The <code>DisplayMessages</code> component should have an initial state equal to <code>{input: \"\", messages: []}</code>.');"
}
],
"solutions": [
"class DisplayMessages extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n messages: []\n }\n }\n render() {\n return <div/>\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"react": true
},
{
"id": "5a24c314108439a4d4036142",
"title": "Manage State Locally First",
"releasedOn": "December 25, 2017",
"description": [
"Here you'll finish creating the <code>DisplayMessages</code> component.",
"<hr>",
"First, in the <code>render()</code> method, have the component render an <code>input</code> element, <code>button</code> element, and <code>ul</code> element. When the <code>input</code> element changes, it should trigger a <code>handleChange()</code> method. Also, the <code>input</code> element should render the value of <code>input</code> that's in the component's state. The <code>button</code> element should trigger a <code>submitMessage()</code> method when it's clicked.",
"Second, write these two methods. The <code>handleChange()</code> method should update the <code>input</code> with what the user is typing. The <code>submitMessage()</code> method should concatenate the current message (stored in <code>input</code>) to the <code>messages</code> array in local state, and clear the value of the <code>input</code>.",
"Finally, use the <code>ul</code> to map over the array of <code>messages</code> and render it to the screen as a list of <code>li</code> elements."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"class DisplayMessages extends React.Component {",
" constructor(props) {",
" super(props);",
" this.state = {",
" input: '',",
" messages: []",
" }",
" }",
" // add handleChange() and submitMessage() methods here",
"",
" render() {",
" return (",
" <div>",
" <h2>Type in a new Message:</h2>",
" { /* render an input, button, and ul here */ }",
"",
" { /* change code above this line */ }",
" </div>",
" );",
" }",
"};"
],
"tail": [
"ReactDOM.render(<DisplayMessages />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text":
"The <code>DisplayMessages</code> component should initialize with a state equal to <code>{ input: \"\", messages: [] }</code>.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const initialState = mockedComponent.state(); return ( typeof initialState === 'object' && initialState.input === '' && initialState.messages.length === 0); })(), 'The <code>DisplayMessages</code> component should initialize with a state equal to <code>{ input: \"\", messages: [] }</code>.');"
},
{
"text":
"The <code>DisplayMessages</code> component should render a <code>div</code> containing an <code>h2</code> element, a <code>button</code> element, a <code>ul</code> element, and <code>li</code> elements as children.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const state = () => { mockedComponent.setState({messages: ['__TEST__MESSAGE']}); return waitForIt(() => mockedComponent )}; const updated = await state(); assert(updated.find('div').length === 1 && updated.find('h2').length === 1 && updated.find('button').length === 1 && updated.find('ul').length === 1, 'The <code>DisplayMessages</code> component should render a <code>div</code> containing an <code>h2</code> element, a <code>button</code> element, a <code>ul</code> element, and <code>li</code> elements as children.'); }; "
},
{
"text":
"The <code>input</code> element should render the value of <code>input</code> in local state.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const testValue = '__TEST__EVENT__INPUT'; const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const updated = await changed(); assert(updated.find('input').props().value === testValue, 'The <code>input</code> element should render the value of <code>input</code> in local state.'); }; "
},
{
"text":
"Calling the method <code>handleChange</code> should update the <code>input</code> value in state to the current input.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage = '__TEST__EVENT__MESSAGE__'; const changed = () => { causeChange(mockedComponent, testMessage); return waitForIt(() => mockedComponent )}; const afterInput = await changed(); assert(initialState.input === '' && afterInput.state().input === '__TEST__EVENT__MESSAGE__', 'Calling the method <code>handleChange</code> should update the <code>input</code> value in state to the current input.'); }; "
},
{
"text":
"Clicking the <code>Add message</code> button should call the method <code>submitMessage</code> which should add the current <code>input</code> to the <code>messages</code> array in state.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage_1 = '__FIRST__MESSAGE__'; const firstChange = () => { causeChange(mockedComponent, testMessage_1); return waitForIt(() => mockedComponent )}; const firstResult = await firstChange(); const firstSubmit = () => { mockedComponent.find('button').simulate('click'); return waitForIt(() => mockedComponent )}; const afterSubmit_1 = await firstSubmit(); const submitState_1 = afterSubmit_1.state(); const testMessage_2 = '__SECOND__MESSAGE__'; const secondChange = () => { causeChange(mockedComponent, testMessage_2); return waitForIt(() => mockedComponent )}; const secondResult = await secondChange(); const secondSubmit = () => { mockedComponent.find('button').simulate('click'); return waitForIt(() => mockedComponent )}; const afterSubmit_2 = await secondSubmit(); const submitState_2 = afterSubmit_2.state(); assert(initialState.messages.length === 0 && submitState_1.messages.length === 1 && submitState_2.messages.length === 2 && submitState_2.messages[1] === testMessage_2, 'Clicking the <code>Add message</code> button should call the method <code>submitMessage</code> which should add the current <code>input</code> to the <code>messages</code> array in state.'); }; "
},
{
"text":
"The <code>submitMessage</code> method should clear the current input.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(DisplayMessages)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const initialState = mockedComponent.state(); const testMessage = '__FIRST__MESSAGE__'; const firstChange = () => { causeChange(mockedComponent, testMessage); return waitForIt(() => mockedComponent )}; const firstResult = await firstChange(); const firstState = firstResult.state(); const firstSubmit = () => { mockedComponent.find('button').simulate('click'); return waitForIt(() => mockedComponent )}; const afterSubmit = await firstSubmit(); const submitState = afterSubmit.state(); assert(firstState.input === testMessage && submitState.input === '', 'The <code>submitMessage</code> method should clear the current input.'); }; "
}
],
"solutions": [
"class DisplayMessages extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n messages: []\n }\n this.handleChange = this.handleChange.bind(this); \n this.submitMessage = this.submitMessage.bind(this); \n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n submitMessage() {\n const currentMessage = this.state.input;\n this.setState({\n input: '',\n messages: this.state.messages.concat(currentMessage)\n });\n }\n render() {\n return (\n <div>\n <h2>Type in a new Message:</h2>\n <input\n value={this.state.input}\n onChange={this.handleChange}/><br/>\n <button onClick={this.submitMessage}>Submit</button>\n <ul>\n {this.state.messages.map( (message, idx) => {\n return (\n <li key={idx}>{message}</li>\n )\n })\n }\n </ul>\n </div>\n );\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036143",
"title": "Extract State Logic to Redux",
"releasedOn": "December 25, 2017",
"description": [
"Now that you finished the React component, you need to move the logic it's performing locally in its <code>state</code> into Redux. This is the first step to connect the simple React app to Redux. The only functionality your app has is to add new messages from the user to an unordered list. The example is simple in order to demonstrate how React and Redux work together.",
"<hr>",
"First, define an action type 'ADD' and set it to a const <code>ADD</code>. Next, define an action creator <code>addMessage()</code> which creates the action to add a message. You'll need to pass a <code>message</code> to this action creator and include the message in the returned <code>action</code>.",
"Then create a reducer called <code>messageReducer()</code> that handles the state for the messages. The initial state should equal an empty array. This reducer should add a message to the array of messages held in state, or return the current state. Finally, create your Redux store and pass it the reducer."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"// define ADD, addMessage(), messageReducer(), and store here:",
""
],
"head": [],
"tail": []
}
},
"tests": [
{
"text":
"The const <code>ADD</code> should exist and hold a value equal to the string <code>ADD</code>",
"testString":
"assert(ADD === 'ADD', 'The const <code>ADD</code> should exist and hold a value equal to the string <code>ADD</code>');"
},
{
"text":
"The action creator <code>addMessage</code> should return an object with <code>type</code> equal to <code>ADD</code> and message equal to the message that is passed in.",
"testString":
"assert((function() { const addAction = addMessage('__TEST__MESSAGE__'); return addAction.type === ADD && addAction.message === '__TEST__MESSAGE__'; })(), 'The action creator <code>addMessage</code> should return an object with <code>type</code> equal to <code>ADD</code> and message equal to the message that is passed in.');"
},
{
"text": "<code>messageReducer</code> should be a function.",
"testString":
"assert(typeof messageReducer === 'function', '<code>messageReducer</code> should be a function.');"
},
{
"text":
"The store should exist and have an initial state set to an empty array.",
"testString":
"assert((function() { const initialState = store.getState(); return typeof store === 'object' && initialState.length === 0; })(), 'The store should exist and have an initial state set to an empty array.');"
},
{
"text":
"Dispatching <code>addMessage</code> against the store should immutably add a new message to the array of messages held in state.",
"testString":
"assert((function() { const initialState = store.getState(); const isFrozen = DeepFreeze(initialState); store.dispatch(addMessage('__A__TEST__MESSAGE')); const addState = store.getState(); return (isFrozen && addState[0] === '__A__TEST__MESSAGE'); })(), 'Dispatching <code>addMessage</code> against the store should immutably add a new message to the array of messages held in state.');"
},
{
"text":
"The <code>messageReducer</code> should return the current state if called with any other actions.",
"testString":
"assert((function() { const addState = store.getState(); store.dispatch({type: 'FAKE_ACTION'}); const testState = store.getState(); return (addState === testState); })(), 'The <code>messageReducer</code> should return the current state if called with any other actions.');"
}
],
"solutions": [
"const ADD = 'ADD';\n\nconst addMessage = (message) => {\n return {\n type: ADD,\n message\n }\n};\n\nconst messageReducer = (state = [], action) => {\n switch (action.type) {\n case ADD:\n return [\n ...state,\n action.message\n ];\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(messageReducer);"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036144",
"title": "Use Provider to Connect Redux to React",
"releasedOn": "December 25, 2017",
"description": [
"In the last challenge, you created a Redux store to handle the messages array and created an action for adding new messages. The next step is to provide React access to the Redux store and the actions it needs to dispatch updates. React Redux provides its <code>react-redux</code> package to help accomplish these tasks.",
"React Redux provides a small API with two key features: <code>Provider</code> and <code>connect</code>. Another challenge covers <code>connect</code>. The <code>Provider</code> is a wrapper component from React Redux that wraps your React app. This wrapper then allows you to access the Redux <code>store</code> and <code>dispatch</code> functions throughout your component tree. <code>Provider</code> takes two props, the Redux store and the child components of your app. Defining the <code>Provider</code> for an App component might look like this:",
"<blockquote>&lt;Provider store={store}&gt;<br>&nbsp;&nbsp;&lt;App/&gt;<br>&lt;/Provider&gt;</blockquote>",
"<hr>",
"The code editor now shows all your Redux and React code from the past several challenges. It includes the Redux store, actions, and the <code>DisplayMessages</code> component. The only new piece is the <code>AppWrapper</code> component at the bottom. Use this top level component to render the <code>Provider</code> from <code>ReactRedux</code>, and pass the Redux store as a prop. Then render the <code>DisplayMessages</code> component as a child. Once you are finished, you should see your React component rendered to the page.",
"<strong>Note:</strong>&nbsp;React Redux is available as a global variable here, so you can access the Provider with dot notation. The code in the editor takes advantage of this and sets it to a constant <code>Provider</code> for you to use in the <code>AppWrapper</code> render method."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"// Redux Code:",
"const ADD = 'ADD';",
"",
"const addMessage = (message) => {",
" return {",
" type: ADD,",
" message",
" }",
"};",
"",
"const messageReducer = (state = [], action) => {",
" switch (action.type) {",
" case ADD:",
" return [",
" ...state,",
" action.message",
" ];",
" default:",
" return state;",
" }",
"};",
"",
"",
"",
"const store = Redux.createStore(messageReducer);",
"",
"// React Code:",
"",
"class DisplayMessages extends React.Component {",
" constructor(props) {",
" super(props);",
" this.state = {",
" input: '',",
" messages: []",
" }",
" this.handleChange = this.handleChange.bind(this);",
" this.submitMessage = this.submitMessage.bind(this);",
" }",
" handleChange(event) {",
" this.setState({",
" input: event.target.value",
" });",
" }",
" submitMessage() {",
" const currentMessage = this.state.input;",
" this.setState({",
" input: '',",
" messages: this.state.messages.concat(currentMessage)",
" });",
" }",
" render() {",
" return (",
" <div>",
" <h2>Type in a new Message:</h2>",
" <input",
" value={this.state.input}",
" onChange={this.handleChange}/><br/>",
" <button onClick={this.submitMessage}>Submit</button>",
" <ul>",
" {this.state.messages.map( (message, idx) => {",
" return (",
" <li key={idx}>{message}</li>",
" )",
" })",
" }",
" </ul>",
" </div>",
" );",
" }",
"};",
"",
"const Provider = ReactRedux.Provider;",
"",
"class AppWrapper extends React.Component {",
" // render the Provider here",
"",
" // change code above this line",
"};"
],
"tail": [
"ReactDOM.render(<AppWrapper />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text": "The <code>AppWrapper</code> should render.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })(), 'The <code>AppWrapper</code> should render.');"
},
{
"text":
"The <code>Provider</code> wrapper component should have a prop of <code>store</code> passed to it, equal to the Redux store.",
"testString":
"getUserInput => assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return getUserInput('index').replace(/\\s/g,'').includes('<Providerstore={store}>'); })(), 'The <code>Provider</code> wrapper component should have a prop of <code>store</code> passed to it, equal to the Redux store.');"
},
{
"text":
"<code>DisplayMessages</code> should render as a child of <code>AppWrapper</code>.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').find('DisplayMessages').length === 1; })(), '<code>DisplayMessages</code> should render as a child of <code>AppWrapper</code>.');"
},
{
"text":
"The <code>DisplayMessages</code> component should render an h2, input, button, and <code>ul</code> element.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('div').length === 1 && mockedComponent.find('h2').length === 1 && mockedComponent.find('button').length === 1 && mockedComponent.find('ul').length === 1; })(), 'The <code>DisplayMessages</code> component should render an h2, input, button, and <code>ul</code> element.');"
}
],
"solutions": [
"// Redux Code:\nconst ADD = 'ADD';\n\nconst addMessage = (message) => {\n return {\n type: ADD,\n message\n }\n};\n\nconst messageReducer = (state = [], action) => {\n switch (action.type) {\n case ADD:\n return [\n ...state,\n action.message\n ];\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(messageReducer);\n\n// React Code:\n\nclass DisplayMessages extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n messages: []\n }\n this.handleChange = this.handleChange.bind(this); \n this.submitMessage = this.submitMessage.bind(this); \n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n submitMessage() {\n const currentMessage = this.state.input;\n this.setState({\n input: '',\n messages: this.state.messages.concat(currentMessage)\n });\n }\n render() {\n return (\n <div>\n <h2>Type in a new Message:</h2>\n <input\n value={this.state.input}\n onChange={this.handleChange}/><br/>\n <button onClick={this.submitMessage}>Submit</button>\n <ul>\n {this.state.messages.map( (message, idx) => {\n return (\n <li key={idx}>{message}</li>\n )\n })\n }\n </ul>\n </div>\n );\n }\n};\n\nconst Provider = ReactRedux.Provider;\n\nclass AppWrapper extends React.Component {\n // change code below this line\n render() {\n return (\n <Provider store = {store}>\n <DisplayMessages/>\n </Provider>\n );\n }\n // change code above this line\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036145",
"title": "Map State to Props",
"releasedOn": "December 25, 2017",
"description": [
"The <code>Provider</code> component allows you to provide <code>state</code> and <code>dispatch</code> to your React components, but you must specify exactly what state and actions you want. This way, you make sure that each component only has access to the state it needs. You accomplish this by creating two functions: <code>mapStateToProps()</code> and <code>mapDispatchToProps()</code>.",
"In these functions, you declare what pieces of state you want to have access to and which action creators you need to be able to dispatch. Once these functions are in place, you'll see how to use the React Redux <code>connect</code> method to connect them to your components in another challenge.",
"<strong>Note:</strong>&nbsp;Behind the scenes, React Redux uses the <code>store.subscribe()</code> method to implement <code>mapStateToProps()</code>.",
"<hr>",
"Create a function <code>mapStateToProps()</code>. This function should take <code>state</code> as an argument, then return an object which maps that state to specific property names. These properties will become accessible to your component via <code>props</code>. Since this example keeps the entire state of the app in a single array, you can pass that entire state to your component. Create a property <code>messages</code> in the object that's being returned, and set it to <code>state</code>."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"const state = [];",
"",
"// change code below this line",
""
],
"head": [],
"tail": []
}
},
"tests": [
{
"text": "The const <code>state</code> should be an empty array.",
"testString":
"assert(Array.isArray(state) && state.length === 0, 'The const <code>state</code> should be an empty array.');"
},
{
"text": "<code>mapStateToProps</code> should be a function.",
"testString":
"assert(typeof mapStateToProps === 'function', '<code>mapStateToProps</code> should be a function.');"
},
{
"text": "<code>mapStateToProps</code> should return an object.",
"testString":
"assert(typeof mapStateToProps() === 'object', '<code>mapStateToProps</code> should return an object.');"
},
{
"text":
"Passing an array as state to <code>mapStateToProps</code> should return this array assigned to a key of <code>messages</code>.",
"testString":
"assert(mapStateToProps(['messages']).messages.pop() === 'messages', 'Passing an array as state to <code>mapStateToProps</code> should return this array assigned to a key of <code>messages</code>.');"
}
],
"solutions": [
"const state = [];\n\n// change code below this line\n\nconst mapStateToProps = (state) => {\n return {\n messages: state\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036146",
"title": "Map Dispatch to Props",
"releasedOn": "December 25, 2017",
"description": [
"The <code>mapDispatchToProps()</code> function is used to provide specific action creators to your React components so they can dispatch actions against the Redux store. It's similar in structure to the <code>mapStateToProps()</code> function you wrote in the last challenge. It returns an object that maps dispatch actions to property names, which become component <code>props</code>. However, instead of returning a piece of <code>state</code>, each property returns a function that calls <code>dispatch</code> with an action creator and any relevant action data. You have access to this <code>dispatch</code> because it's passed in to <code>mapDispatchToProps()</code> as a parameter when you define the function, just like you passed <code>state</code> to <code>mapStateToProps()</code>. Behind the scenes, React Redux is using Redux's <code>store.dispatch()</code> to conduct these dispatches with <code>mapDispatchToProps()</code>. This is similar to how it uses <code>store.subscribe()</code> for components that are mapped to <code>state</code>.",
"For example, you have a <code>loginUser()</code> action creator that takes a <code>username</code> as an action payload. The object returned from <code>mapDispatchToProps()</code> for this action creator would look something like:",
"<blockquote>{<br>&nbsp;&nbsp;submitLoginUser: function(username) {<br>&nbsp;&nbsp;&nbsp;&nbsp;dispatch(loginUser(username));<br>&nbsp;&nbsp;}<br>}</blockquote>",
"<hr>",
"The code editor provides an action creator called <code>addMessage()</code>. Write the function <code>mapDispatchToProps()</code> that takes <code>dispatch</code> as an argument, then returns an object. The object should have a property <code>submitNewMessage</code> set to the dispatch function, which takes a parameter for the new message to add when it dispatches <code>addMessage()</code>."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"const addMessage = (message) => {",
" return {",
" type: 'ADD',",
" message: message",
" }",
"};",
"",
"// change code below this line",
""
],
"head": [],
"tail": []
}
},
"tests": [
{
"text":
"<code>addMessage</code> should return an object with keys <code>type</code> and <code>message</code>.",
"testString":
"assert((function() { const addMessageTest = addMessage(); return ( addMessageTest.hasOwnProperty('type') && addMessageTest.hasOwnProperty('message')); })(), '<code>addMessage</code> should return an object with keys <code>type</code> and <code>message</code>.');"
},
{
"text": "<code>mapDispatchToProps</code> should be a function.",
"testString":
"assert(typeof mapDispatchToProps === 'function', '<code>mapDispatchToProps</code> should be a function.');"
},
{
"text": "<code>mapDispatchToProps</code> should return an object.",
"testString":
"assert(typeof mapDispatchToProps() === 'object', '<code>mapDispatchToProps</code> should return an object.');"
},
{
"text":
"Dispatching <code>addMessage</code> with <code>submitNewMessage</code> from <code>mapDispatchToProps</code> should return a message to the dispatch function.",
"testString":
"assert((function() { let testAction; const dispatch = (fn) => { testAction = fn; }; let dispatchFn = mapDispatchToProps(dispatch); dispatchFn.submitNewMessage('__TEST__MESSAGE__'); return (testAction.type === 'ADD' && testAction.message === '__TEST__MESSAGE__'); })(), 'Dispatching <code>addMessage</code> with <code>submitNewMessage</code> from <code>mapDispatchToProps</code> should return a message to the dispatch function.');"
}
],
"solutions": [
"const addMessage = (message) => {\n return {\n type: 'ADD',\n message: message\n }\n};\n\n// change code below this line\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n submitNewMessage: function(message) {\n dispatch(addMessage(message));\n }\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036147",
"title": "Connect Redux to React",
"releasedOn": "December 25, 2017",
"description": [
"Now that you've written both the <code>mapStateToProps()</code> and the <code>mapDispatchToProps()</code> functions, you can use them to map <code>state</code> and <code>dispatch</code> to the <code>props</code> of one of your React components. The <code>connect</code> method from React Redux can handle this task. This method takes two optional arguments, <code>mapStateToProps()</code> and <code>mapDispatchToProps()</code>. They are optional because you may have a component that only needs access to <code>state</code> but doesn't need to dispatch any actions, or vice versa.",
"To use this method, pass in the functions as arguments, and immediately call the result with your component. This syntax is a little unusual and looks like:",
"<code>connect(mapStateToProps, mapDispatchToProps)(MyComponent)</code>",
"<strong>Note:</strong>&nbsp;If you want to omit one of the arguments to the <code>connect</code> method, you pass <code>null</code> in its place.",
"<hr>",
"The code editor has the <code>mapStateToProps()</code> and <code>mapDispatchToProps()</code> functions and a new React component called <code>Presentational</code>. Connect this component to Redux with the <code>connect</code> method from the <code>ReactRedux</code> global object, and call it immediately on the <code>Presentational</code> component. Assign the result to a new <code>const</code> called <code>ConnectedComponent</code> that represents the connected component. That's it, now you're connected to Redux! Try changing either of <code>connect</code>'s arguments to <code>null</code> and observe the test results."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"const addMessage = (message) => {",
" return {",
" type: 'ADD',",
" message: message",
" }",
"};",
"",
"const mapStateToProps = (state) => {",
" return {",
" messages: state",
" }",
"};",
"",
"const mapDispatchToProps = (dispatch) => {",
" return {",
" submitNewMessage: (message) => {",
" dispatch(addMessage(message));",
" }",
" }",
"};",
"",
"class Presentational extends React.Component {",
" constructor(props) {",
" super(props);",
" }",
" render() {",
" return <h3>This is a Presentational Component</h3>",
" }",
"};",
"",
"const connect = ReactRedux.connect;",
"// change code below this line",
""
],
"tail": [
"",
"const store = Redux.createStore(",
" (state = '__INITIAL__STATE__', action) => state",
");",
"class AppWrapper extends React.Component {",
" render() {",
" return (",
" <ReactRedux.Provider store = {store}>",
" <ConnectedComponent/>",
" </ReactRedux.Provider>",
" );",
" }",
"};",
"ReactDOM.render(<AppWrapper />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text": "The <code>Presentational</code> component should render.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('Presentational').length === 1; })(), 'The <code>Presentational</code> component should render.');"
},
{
"text":
"The <code>Presentational</code> component should receive a prop <code>messages</code> via <code>connect</code>.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const props = mockedComponent.find('Presentational').props(); return props.messages === '__INITIAL__STATE__'; })(), 'The <code>Presentational</code> component should receive a prop <code>messages</code> via <code>connect</code>.');"
},
{
"text":
"The <code>Presentational</code> component should receive a prop <code>submitNewMessage</code> via <code>connect</code>.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const props = mockedComponent.find('Presentational').props(); return typeof props.submitNewMessage === 'function'; })(), 'The <code>Presentational</code> component should receive a prop <code>submitNewMessage</code> via <code>connect</code>.');"
}
],
"solutions": [
"const addMessage = (message) => {\n return {\n type: 'ADD',\n message: message\n }\n};\n\nconst mapStateToProps = (state) => {\n return {\n messages: state\n }\n};\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n submitNewMessage: (message) => {\n dispatch(addMessage(message));\n }\n }\n};\n\nclass Presentational extends React.Component {\n constructor(props) {\n super(props);\n }\n render() {\n return <h3>This is a Presentational Component</h3>\n }\n};\n\nconst connect = ReactRedux.connect;\n// change code below this line\n\nconst ConnectedComponent = connect(mapStateToProps, mapDispatchToProps)(Presentational); \n"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036148",
"title": "Connect Redux to the Messages App",
"releasedOn": "December 25, 2017",
"description": [
"Now that you understand how to use <code>connect</code> to connect React to Redux, you can apply what you've learned to your React component that handles messages.",
"In the last lesson, the component you connected to Redux was named <code>Presentational</code>, and this wasn't arbitrary. This term <i>generally</i> refers to React components that are not directly connected to Redux. They are simply responsible for the presentation of UI and do this as a function of the props they receive. By contrast, container components are connected to Redux. These are typically responsible for dispatching actions to the store and often pass store state to child components as props.",
"<hr>",
"The code editor has all the code you've written in this section so far. The only change is that the React component is renamed to <code>Presentational</code>. Create a new component held in a constant called <code>Container</code> that uses <code>connect</code> to connect the <code>Presentational</code> component to Redux. Then, in the <code>AppWrapper</code>, render the React Redux <code>Provider</code> component. Pass <code>Provider</code> the Redux <code>store</code> as a prop and render <code>Container</code> as a child. Once everything is setup, you will see the messages app rendered to the page again."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"// Redux:",
"const ADD = 'ADD';",
"",
"const addMessage = (message) => {",
" return {",
" type: ADD,",
" message: message",
" }",
"};",
"",
"const messageReducer = (state = [], action) => {",
" switch (action.type) {",
" case ADD:",
" return [",
" ...state,",
" action.message",
" ];",
" default:",
" return state;",
" }",
"};",
"",
"const store = Redux.createStore(messageReducer);",
"",
"// React:",
"class Presentational extends React.Component {",
" constructor(props) {",
" super(props);",
" this.state = {",
" input: '',",
" messages: []",
" }",
" this.handleChange = this.handleChange.bind(this);",
" this.submitMessage = this.submitMessage.bind(this);",
" }",
" handleChange(event) {",
" this.setState({",
" input: event.target.value",
" });",
" }",
" submitMessage() {",
" const currentMessage = this.state.input;",
" this.setState({",
" input: '',",
" messages: this.state.messages.concat(currentMessage)",
" });",
" }",
" render() {",
" return (",
" <div>",
" <h2>Type in a new Message:</h2>",
" <input",
" value={this.state.input}",
" onChange={this.handleChange}/><br/>",
" <button onClick={this.submitMessage}>Submit</button>",
" <ul>",
" {this.state.messages.map( (message, idx) => {",
" return (",
" <li key={idx}>{message}</li>",
" )",
" })",
" }",
" </ul>",
" </div>",
" );",
" }",
"};",
"",
"// React-Redux:",
"const mapStateToProps = (state) => {",
" return { messages: state }",
"};",
"",
"const mapDispatchToProps = (dispatch) => {",
" return {",
" submitNewMessage: (newMessage) => {",
" dispatch(addMessage(newMessage))",
" }",
" }",
"};",
"",
"const Provider = ReactRedux.Provider;",
"const connect = ReactRedux.connect;",
"",
"// define the Container component here:",
"",
"",
"class AppWrapper extends React.Component {",
" constructor(props) {",
" super(props);",
" }",
" render() {",
" // complete the return statement:",
" return (null);",
" }",
"};"
],
"tail": [
"ReactDOM.render(<AppWrapper />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text": "The <code>AppWrapper</code> should render to the page.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })(), 'The <code>AppWrapper</code> should render to the page.');"
},
{
"text":
"The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('Presentational').length === 1; })(), 'The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.');"
},
{
"text":
"The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); return ( PresentationalComponent.find('div').length === 1 && PresentationalComponent.find('h2').length === 1 && PresentationalComponent.find('button').length === 1 && PresentationalComponent.find('ul').length === 1 ); })(), 'The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.');"
},
{
"text":
"The <code>Presentational</code> component should receive <code>messages</code> from the Redux store as a prop.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); const props = PresentationalComponent.props(); return Array.isArray(props.messages); })(), 'The <code>Presentational</code> component should receive <code>messages</code> from the Redux store as a prop.');"
},
{
"text":
"The <code>Presentational</code> component should receive the <code>submitMessage</code> action creator as a prop.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); const props = PresentationalComponent.props(); return typeof props.submitNewMessage === 'function'; })(), 'The <code>Presentational</code> component should receive the <code>submitMessage</code> action creator as a prop.');"
}
],
"solutions": [
"// Redux:\nconst ADD = 'ADD';\n\nconst addMessage = (message) => {\n return {\n type: ADD,\n message: message\n }\n};\n\nconst messageReducer = (state = [], action) => {\n switch (action.type) {\n case ADD:\n return [\n ...state,\n action.message\n ];\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(messageReducer);\n\n// React:\nclass Presentational extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: '',\n messages: []\n }\n this.handleChange = this.handleChange.bind(this); \n this.submitMessage = this.submitMessage.bind(this); \n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n submitMessage() {\n const currentMessage = this.state.input;\n this.setState({\n input: '',\n messages: this.state.messages.concat(currentMessage)\n });\n }\n render() {\n return (\n <div>\n <h2>Type in a new Message:</h2>\n <input\n value={this.state.input}\n onChange={this.handleChange}/><br/>\n <button onClick={this.submitMessage}>Submit</button>\n <ul>\n {this.state.messages.map( (message, idx) => {\n return (\n <li key={idx}>{message}</li>\n )\n })\n }\n </ul>\n </div>\n );\n }\n};\n\n// React-Redux:\nconst mapStateToProps = (state) => {\n return { messages: state }\n};\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n submitNewMessage: (newMessage) => {\n dispatch(addMessage(newMessage))\n }\n }\n};\n\nconst Provider = ReactRedux.Provider;\nconst connect = ReactRedux.connect;\n\n// define the Container component here:\nconst Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);\n\nclass AppWrapper extends React.Component {\n constructor(props) {\n super(props);\n }\n render() {\n // complete the return statement:\n return (\n <Provider store={store}>\n <Container/>\n </Provider>\n );\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d4036149",
"title": "Extract Local State into Redux",
"releasedOn": "December 25, 2017",
"description": [
"You're almost done! Recall that you wrote all the Redux code so that Redux could control the state management of your React messages app. Now that Redux is connected, you need to extract the state management out of the <code>Presentational</code> component and into Redux. Currently, you have Redux connected, but you are handling the state locally within the <code>Presentational</code> component.",
"<hr>",
"In the <code>Presentational</code> component, first, remove the <code>messages</code> property in the local <code>state</code>. These messages will be managed by Redux. Next, modify the <code>submitMessage()</code> method so that it dispatches <code>submitNewMessage()</code> from <code>this.props</code>, and pass in the current message input from local <code>state</code> as an argument. Because you removed <code>messages</code> from local state, remove the <code>messages</code> property from the call to <code>this.setState()</code> here as well. Finally, modify the <code>render()</code> method so that it maps over the messages received from <code>props</code> rather than <code>state</code>.",
"Once these changes are made, the app will continue to function the same, except Redux manages the state. This example also illustrates how a component may have local <code>state</code>: your component still tracks user input locally in its own <code>state</code>. You can see how Redux provides a useful state management framework on top of React. You achieved the same result using only React's local state at first, and this is usually possible with simple apps. However, as your apps become larger and more complex, so does your state management, and this is the problem Redux solves."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"// Redux:",
"const ADD = 'ADD';",
"",
"const addMessage = (message) => {",
" return {",
" type: ADD,",
" message: message",
" }",
"};",
"",
"const messageReducer = (state = [], action) => {",
" switch (action.type) {",
" case ADD:",
" return [",
" ...state,",
" action.message",
" ];",
" default:",
" return state;",
" }",
"};",
"",
"const store = Redux.createStore(messageReducer);",
"",
"// React:",
"const Provider = ReactRedux.Provider;",
"const connect = ReactRedux.connect;",
"",
"// Change code below this line",
"class Presentational extends React.Component {",
" constructor(props) {",
" super(props);",
" this.state = {",
" input: '',",
" messages: []",
" }",
" this.handleChange = this.handleChange.bind(this);",
" this.submitMessage = this.submitMessage.bind(this);",
" }",
" handleChange(event) {",
" this.setState({",
" input: event.target.value",
" });",
" }",
" submitMessage() {",
" this.setState({",
" input: '',",
" messages: this.state.messages.concat(this.state.input)",
" });",
" }",
" render() {",
" return (",
" <div>",
" <h2>Type in a new Message:</h2>",
" <input",
" value={this.state.input}",
" onChange={this.handleChange}/><br/>",
" <button onClick={this.submitMessage}>Submit</button>",
" <ul>",
" {this.state.messages.map( (message, idx) => {",
" return (",
" <li key={idx}>{message}</li>",
" )",
" })",
" }",
" </ul>",
" </div>",
" );",
" }",
"};",
"// Change code above this line",
"",
"const mapStateToProps = (state) => {",
" return {messages: state}",
"};",
"",
"const mapDispatchToProps = (dispatch) => {",
" return {",
" submitNewMessage: (message) => {",
" dispatch(addMessage(message))",
" }",
" }",
"};",
"",
"const Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);",
"",
"class AppWrapper extends React.Component {",
" render() {",
" return (",
" <Provider store={store}>",
" <Container/>",
" </Provider>",
" );",
" }",
"};"
],
"tail": [
"ReactDOM.render(<AppWrapper />, document.getElementById('root'))"
],
"head": []
}
},
"tests": [
{
"text": "The <code>AppWrapper</code> should render to the page.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('AppWrapper').length === 1; })(), 'The <code>AppWrapper</code> should render to the page.');"
},
{
"text":
"The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); return mockedComponent.find('Presentational').length === 1; })(), 'The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.');"
},
{
"text":
"The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); return ( PresentationalComponent.find('div').length === 1 && PresentationalComponent.find('h2').length === 1 && PresentationalComponent.find('button').length === 1 && PresentationalComponent.find('ul').length === 1 ); })(), 'The <code>Presentational</code> component should render an <code>h2</code>, <code>input</code>, <code>button</code>, and <code>ul</code> elements.');"
},
{
"text":
"The <code>Presentational</code> component should receive <code>messages</code> from the Redux store as a prop.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); const props = PresentationalComponent.props(); return Array.isArray(props.messages); })(), 'The <code>Presentational</code> component should receive <code>messages</code> from the Redux store as a prop.');"
},
{
"text":
"The <code>Presentational</code> component should receive the <code>submitMessage</code> action creator as a prop.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalComponent = mockedComponent.find('Presentational'); const props = PresentationalComponent.props(); return typeof props.submitNewMessage === 'function'; })(), 'The <code>Presentational</code> component should receive the <code>submitMessage</code> action creator as a prop.');"
},
{
"text":
"The state of the <code>Presentational</code> component should contain one property, <code>input</code>, which is initialized to an empty string.",
"testString":
"assert((function() { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const PresentationalState = mockedComponent.find('Presentational').instance().state; return typeof PresentationalState.input === 'string' && Object.keys(PresentationalState).length === 1; })(), 'The state of the <code>Presentational</code> component should contain one property, <code>input</code>, which is initialized to an empty string.');"
},
{
"text":
"Typing in the <code>input</code> element should update the state of the <code>Presentational</code> component.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const testValue = '__MOCK__INPUT__'; const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); let initialInput = mockedComponent.find('Presentational').find('input'); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const updated = await changed(); const updatedInput = updated.find('Presentational').find('input'); assert(initialInput.props().value === '' && updatedInput.props().value === '__MOCK__INPUT__', 'Typing in the <code>input</code> element should update the state of the <code>Presentational</code> component.'); }; "
},
{
"text":
"Dispatching the <code>submitMessage</code> on the <code>Presentational</code> component should update Redux store and clear the input in local state.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find('Presentational').props(); const testValue = '__TEST__EVENT__INPUT__'; const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find('button').simulate('click'); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find('input').props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find('Presentational').props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find('input').props().value === '', 'Dispatching the <code>submitMessage</code> on the <code>Presentational</code> component should update Redux store and clear the input in local state.'); }; "
},
{
"text":
"The <code>Presentational</code> component should render the <code>messages</code> from the Redux store.",
"testString":
"async () => { const mockedComponent = Enzyme.mount(React.createElement(AppWrapper)); const waitForIt = (fn) => new Promise((resolve, reject) => setTimeout(() => resolve(fn()), 100)); let beforeProps = mockedComponent.find('Presentational').props(); const testValue = '__TEST__EVENT__INPUT__'; const causeChange = (c, v) => c.find('input').simulate('change', { target: { value: v }}); const changed = () => { causeChange(mockedComponent, testValue); return waitForIt(() => mockedComponent )}; const clickButton = () => { mockedComponent.find('button').simulate('click'); return waitForIt(() => mockedComponent )}; const afterChange = await changed(); const afterChangeInput = afterChange.find('input').props().value; const afterClick = await clickButton(); const afterProps = mockedComponent.find('Presentational').props(); assert(beforeProps.messages.length === 0 && afterChangeInput === testValue && afterProps.messages.pop() === testValue && afterClick.find('input').props().value === '' && afterClick.find('ul').childAt(0).text() === testValue, 'The <code>Presentational</code> component should render the <code>messages</code> from the Redux store.'); }; "
}
],
"solutions": [
"// Redux:\nconst ADD = 'ADD';\n\nconst addMessage = (message) => {\n return {\n type: ADD,\n message: message\n }\n};\n\nconst messageReducer = (state = [], action) => {\n switch (action.type) {\n case ADD:\n return [\n ...state,\n action.message\n ];\n default:\n return state;\n }\n};\n\nconst store = Redux.createStore(messageReducer);\n\n// React:\nconst Provider = ReactRedux.Provider;\nconst connect = ReactRedux.connect;\n\n// Change code below this line\nclass Presentational extends React.Component {\n constructor(props) {\n super(props);\n this.state = {\n input: ''\n }\n this.handleChange = this.handleChange.bind(this); \n this.submitMessage = this.submitMessage.bind(this); \n }\n handleChange(event) {\n this.setState({\n input: event.target.value\n });\n }\n submitMessage() {\n this.props.submitNewMessage(this.state.input);\n this.setState({\n input: ''\n });\n }\n render() {\n return (\n <div>\n <h2>Type in a new Message:</h2>\n <input\n value={this.state.input}\n onChange={this.handleChange}/><br/>\n <button onClick={this.submitMessage}>Submit</button>\n <ul>\n {this.props.messages.map( (message, idx) => {\n return (\n <li key={idx}>{message}</li>\n )\n })\n }\n </ul>\n </div>\n );\n }\n};\n// Change code above this line\n\nconst mapStateToProps = (state) => {\n return {messages: state}\n};\n\nconst mapDispatchToProps = (dispatch) => {\n return {\n submitNewMessage: (message) => {\n dispatch(addMessage(message))\n }\n }\n};\n\nconst Container = connect(mapStateToProps, mapDispatchToProps)(Presentational);\n\nclass AppWrapper extends React.Component {\n render() {\n return (\n <Provider store={store}>\n <Container/>\n </Provider>\n );\n }\n};"
],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
},
{
"id": "5a24c314108439a4d403614a",
"title": "Moving Forward From Here",
"releasedOn": "December 25, 2017",
"description": [
"Congratulations! You finished the lessons on React and Redux. There's one last item worth pointing out before you move on. Typically, you won't write React apps in a code editor like this. This challenge gives you a glimpse of what the syntax looks like if you're working with npm and a file system on your own machine. The code should look similar, except for the use of <code>import</code> statements (these pull in all of the dependencies that have been provided for you in the challenges). The \"Managing Packages with npm\" section covers npm in more detail.",
"Finally, writing React and Redux code generally requires some configuration. This can get complicated quickly. If you are interested in experimenting on your own machine, the",
"<a id='CRA' target ='_blank' href='https://github.com/facebookincubator/create-react-app'>Create React App</a> comes configured and ready to go.",
"Alternatively, you can enable Babel as a JavaScript Preprocessor in CodePen, add React and ReactDOM as external JavaScript resources, and work there as well.",
"<hr>",
"Log the message <code>'Now I know React and Redux!'</code> to the console."
],
"files": {
"indexjsx": {
"key": "indexjsx",
"ext": "jsx",
"name": "index",
"contents": [
"// import React from 'react'",
"// import ReactDOM from 'react-dom'",
"// import { Provider, connect } from 'react-redux'",
"// import { createStore, combineReducers, applyMiddleware } from 'redux'",
"// import thunk from 'redux-thunk'",
"",
"// import rootReducer from './redux/reducers'",
"// import App from './components/App'",
"",
"// const store = createStore(",
"// rootReducer,",
"// applyMiddleware(thunk)",
"// );",
"",
"// ReactDOM.render(",
"// <Provider store={store}>",
"// <App/>",
"// </Provider>,",
"// document.getElementById('root')",
"// );",
"",
"// change code below this line",
""
],
"head": [],
"tail": []
}
},
"tests": [
{
"text":
"The message <code>Now I know React and Redux!</code> should be logged to the console.",
"testString":
"assert(editor.getValue().includes('console.log(\"Now I know React and Redux!\")') || editor.getValue().includes('console.log(\\'Now I know React and Redux!\\')'), 'The message <code>Now I know React and Redux!</code> should be logged to the console.');"
}
],
"solutions": ["console.log('Now I know React and Redux!');"],
"challengeType": 6,
"isRequired": false,
"translations": {},
"reactRedux": true
}
]
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,659 @@
{
"name": "Sass",
"order": 4,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7dbd367417b2b2512bb4",
"title": "Store Data with Sass Variables",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"One feature of Sass that's different than CSS is it uses variables. They are declared and set to store data, similar to JavaScript.",
"In JavaScript, variables are defined using the <code>let</code> and <code>const</code> keywords. In Sass, variables start with a <code>$</code> followed by the variable name.",
"Here are a couple examples:",
"<blockquote>$main-fonts: Arial, sans-serif;<br>$headings-color: green;<br><br>//To use variables:<br>h1 {<br>&nbsp;&nbsp;font-family: $main-fonts;<br>&nbsp;&nbsp;color: $headings-color;<br>}</blockquote>",
"One example where variables are useful is when a number of elements need to be the same color. If that color is changed, the only place to edit the code is the variable value.",
"<hr>",
"Create a variable <code>$text-color</code> and set it to red. Then change the value of the <code>color</code> property for the <code>.blog-post</code> and <code>h2</code> to the <code>$text-color</code> variable."
],
"tests": [
{
"text": "Your code should have a Sass variable declared for <code>$text-color</code> with a value of red.",
"testString": "assert(code.match(/\\$text-color:\\s*?red;/g), 'Your code should have a Sass variable declared for <code>$text-color</code> with a value of red.');"
},
{
"text": "Your code should use the <code>$text-color</code> variable to change the <code>color</code> for the <code>.blog-post</code> and <code>h2</code> items.",
"testString": "assert(code.match(/color:\\s*?\\$text-color;/g), 'Your code should use the <code>$text-color</code> variable to change the <code>color</code> for the <code>.blog-post</code> and <code>h2</code> items.');"
},
{
"text": "Your <code>.blog-post</code> element should have a </code>color</code> of red.",
"testString": "assert($('.blog-post').css('color') == 'rgb(255, 0, 0)', 'Your <code>.blog-post</code> element should have a </code>color</code> of red.');"
},
{
"text": "Your <code>h2</code> elements should have a </code>color</code> of red.",
"testString": "assert($('h2').css('color') == 'rgb(255, 0, 0)', 'Your <code>h2</code> elements should have a </code>color</code> of red.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" .header{",
" text-align: center;",
" }",
" .blog-post, h2 {",
" color: red;",
" }",
"</style>",
"",
"<h1 class=\"header\">Learn Sass</h1>",
"<div class=\"blog-post\">",
" <h2>Some random title</h2>",
" <p>This is a paragraph with some random text in it</p>",
"</div>",
"<div class=\"blog-post\">",
" <h2>Header #2</h2>",
" <p>Here is some more random text.</p>",
"</div>",
"<div class=\"blog-post\">",
" <h2>Here is another header</h2>",
" <p>Even more random text within a paragraph</p>",
"</div>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbd367417b2b2512bb5",
"title": "Nest CSS with Sass",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"Sass allows <code>nesting</code> of CSS rules, which is a useful way of organizing a style sheet.",
"Normally, each element is targeted on a different line to style it, like so:",
"<blockquote>nav {<br>&nbsp;&nbsp;background-color: red;<br>}<br><br>nav ul {<br>&nbsp;&nbsp;list-style: none;<br>}<br><br>nav ul li {<br>&nbsp;&nbsp;display: inline-block;<br>}</blockquote>",
"For a large project, the CSS file will have many lines and rules. This is where <code>nesting</code> can help organize your code by placing child style rules within the respective parent elements:",
"<blockquote>nav {<br>&nbsp;&nbsp;background-color: red;<br><br>&nbsp;&nbsp;ul {<br>&nbsp;&nbsp;&nbsp;&nbsp;list-style: none;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;li {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;display: inline-block;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br>}<br></blockquote>",
"<hr>",
"Use the <code>nesting</code> technique shown above to re-organize the CSS rules for both children of <code>.blog-post</code> element. For testing purposes, the <code>h1</code> should come before the <code>p</code> element."
],
"tests": [
{
"text": "Your code should re-organize the CSS rules so the <code>h1</code> and <code>p</code> are nested in the <code>.blog-post</code> parent element.",
"testString": "assert(code.match(/\\.blog-post\\s*?{\\s*?h1\\s*?{\\s*?text-align:\\s*?center;\\s*?color:\\s*?blue;\\s*?}\\s*?p\\s*?{\\s*?font-size:\\s*?20px;\\s*?}\\s*?}/gi), 'Your code should re-organize the CSS rules so the <code>h1</code> and <code>p</code> are nested in the <code>.blog-post</code> parent element.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" .blog-post {",
" ",
" }",
" h1 {",
" text-align: center;",
" color: blue;",
" }",
" p {",
" font-size: 20px;",
" }",
"</style>",
"",
"<div class=\"blog-post\">",
" <h1>Blog Title</h1>",
" <p>This is a paragraph</p>",
"</div>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbd367417b2b2512bb6",
"title": "Create Reusable CSS with Mixins",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"In Sass, a <code>mixin</code> is a group of CSS declarations that can be reused throughout the style sheet.",
"Newer CSS features take time before they are fully adopted and ready to use in all browsers. As features are added to browsers, CSS rules using them may need vendor prefixes. Consider \"box-shadow\":",
"<blockquote>div {<br>&nbsp;&nbsp;-webkit-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;-moz-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;-ms-box-shadow: 0px 0px 4px #fff;<br>&nbsp;&nbsp;box-shadow: 0px 0px 4px #fff;<br>}</blockquote>",
"It's a lot of typing to re-write this rule for all the elements that have a <code>box-shadow</code>, or to change each value to test different effects.",
"<code>Mixins</code> are like functions for CSS. Here is how to write one:",
"<blockquote>@mixin box-shadow($x, $y, $blur, $c){ <br>&nbsp;&nbsp;-webkit-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;-moz-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;-ms-box-shadow: $x, $y, $blur, $c;<br>&nbsp;&nbsp;box-shadow: $x, $y, $blur, $c;<br>}</blockquote>",
"The definition starts with <code>@mixin</code> followed by a custom name. The parameters (the <code>$x</code>, <code>$y</code>, <code>$blur</code>, and <code>$c</code> in the example above) are optional.",
"Now any time a <code>box-shadow</code> rule is needed, only a single line calling the <code>mixin</code> replaces having to type all the vendor prefixes. A <code>mixin</code> is called with the <code>@include</code> directive:",
"<blockquote>div {<br>&nbsp;&nbsp;@include box-shadow(0px, 0px, 4px, #fff);<br>}</blockquote>",
"<hr>",
"Write a <code>mixin</code> for <code>border-radius</code> and give it a <code>$radius</code> parameter. It should use all the vendor prefixes from the example. Then use the <code>border-radius</code> <code>mixin</code> to give the <code>#awesome</code> element a border radius of 15px."
],
"tests": [
{
"text": "Your code should declare a <code>mixin</code> named <code>border-radius</code> which has a parameter named <code>$radius</code>.",
"testString": "assert(code.match(/@mixin\\s+?border-radius\\s*?\\(\\s*?\\$radius\\s*?\\)\\s*?{/gi), 'Your code should declare a <code>mixin</code> named <code>border-radius</code> which has a parameter named <code>$radius</code>.');"
},
{
"text": "Your code should include the <code>-webkit-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.",
"testString": "assert(code.match(/-webkit-border-radius:\\s*?\\$radius;/gi), 'Your code should include the <code>-webkit-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');"
},
{
"text": "Your code should include the <code>-moz-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.",
"testString": "assert(code.match(/-moz-border-radius:\\s*?\\$radius;/gi), 'Your code should include the <code>-moz-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');"
},
{
"text": "Your code should include the <code>-ms-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.",
"testString": "assert(code.match(/-ms-border-radius:\\s*?\\$radius;/gi), 'Your code should include the <code>-ms-border-radius</code> vender prefix that uses the <code>$radius</code> parameter.');"
},
{
"text": "Your code should include the general <code>border-radius</code> rule that uses the <code>$radius</code> parameter.",
"testString": "assert(code.match(/border-radius:\\s*?\\$radius;/gi).length == 4, 'Your code should include the general <code>border-radius</code> rule that uses the <code>$radius</code> parameter.');"
},
{
"text": "Your code should call the <code>border-radius mixin</code> using the <code>@include</code> keyword, setting it to 15px.",
"testString": "assert(code.match(/@include\\s+?border-radius\\(\\s*?15px\\s*?\\);/gi), 'Your code should call the <code>border-radius mixin</code> using the <code>@include</code> keyword, setting it to 15px.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" ",
" #awesome {",
" width: 150px;",
" height: 150px;",
" background-color: green;",
" ",
" }",
"</style>",
"",
"<div id=\"awesome\"></div>",
" "
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbe367417b2b2512bb8",
"title": "Use @if and @else to Add Logic To Your Styles",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"The <code>@if</code> directive in Sass is useful to test for a specific case - it works just like the <code>if</code> statement in JavaScript</code>.",
"<blockquote>@mixin make-bold($bool) {<br>&nbsp;&nbsp;@if $bool == true {<br>&nbsp;&nbsp;&nbsp;&nbsp;font-weight: bold;<br>&nbsp;&nbsp;}<br>}</blockquote>",
"And just like in JavaScript, <code>@else if</code> and <code>@else</code> test for more conditions:",
"<blockquote>@mixin text-effect($val) {<br>&nbsp;&nbsp;@if $val == danger {<br>&nbsp;&nbsp;&nbsp;&nbsp;color: red;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;@else if $val == alert {<br>&nbsp;&nbsp;&nbsp;&nbsp;color: yellow;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;@else if $val == success {<br>&nbsp;&nbsp;&nbsp;&nbsp;color: green;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;@else {<br>&nbsp;&nbsp;&nbsp;&nbsp;color: black;<br>&nbsp;&nbsp;}<br>}</blockquote>",
"<hr>",
"Create a <code>mixin</code> called <code>border-stroke</code> that takes a parameter <code>$val</code>. The <code>mixin</code> should check for the following conditions using <code>@if</code>, <code>@else if</code>, and <code>@else</code>:",
"<blockquote>light - 1px solid black<br>medium - 3px solid black<br>heavy - 6px solid black<br>none - no border</blockquote>"
],
"tests": [
{
"text": "Your code should declare a <code>mixin</code> named <code>border-stroke</code> which has a parameter named <code>$val</code>.",
"testString": "assert(code.match(/@mixin\\s+?border-stroke\\s*?\\(\\s*?\\$val\\s*?\\)\\s*?{/gi), 'Your code should declare a <code>mixin</code> named <code>border-stroke</code> which has a parameter named <code>$val</code>.');"
},
{
"text": "Your <code>mixin</code> should have an <code>@if</code> statement to check if <code>$val</code> is light, and to set the <code>border</code> to 1px solid black.",
"testString": "assert(code.match(/@if\\s+?\\$val\\s*?===?\\s*?light\\s*?{\\s*?border\\s*?:\\s*?1px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'Your <code>mixin</code> should have an <code>@if</code> statement to check if <code>$val</code> is light, and to set the <code>border</code> to 1px solid black.');"
},
{
"text": "Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is medium, and to set the <code>border</code> to 3px solid black.",
"testString": "assert(code.match(/@else\\s+?if\\s+?\\$val\\s*?===?\\s*?medium\\s*?{\\s*?border\\s*?:\\s*?3px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is medium, and to set the <code>border</code> to 3px solid black.');"
},
{
"text": "Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is heavy, and to set the <code>border</code> to 6px solid black.",
"testString": "assert(code.match(/@else\\s+?if\\s+?\\$val\\s*?===?\\s*?heavy\\s*?{\\s*?border\\s*?:\\s*?6px\\s+?solid\\s+?black\\s*?;\\s*?}/gi), 'Your <code>mixin</code> should have an <code>@else if</code> statement to check if <code>$val</code> is heavy, and to set the <code>border</code> to 6px solid black.');"
},
{
"text": "Your <code>mixin</code> should have an <code>@else</code> statement to set the <code>border</code> to none.",
"testString": "assert(code.match(/@else\\s*?{\\s*?border\\s*?:\\s*?none\\s*?;\\s*?}/gi), 'Your <code>mixin</code> should have an <code>@else</code> statement to set the <code>border</code> to none.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" ",
" #box {",
" width: 150px;",
" height: 150px;",
" background-color: red;",
" @include border-stroke(medium);",
" } ",
"</style>",
"",
"<div id=\"box\"></div>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbe367417b2b2512bb9",
"title": "Use @for to Create a Sass Loop",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"The <code>@for</code> directive adds styles in a loop, very similar to a <code>for</code> loop in JavaScript.",
"<code>@for</code> is used in two ways: \"start through end\" or \"start to end\". The main difference is that \"start to end\" <em>excludes</em> the end number, and \"start through end\" <em>includes</em> the end number.",
"Here's a start <b>through</b> end example:",
"<blockquote>@for $i from 1 through 12 {<br>&nbsp;&nbsp;.col-#{$i} { width: 100%/12 * $i; }<br>}</blockquote>",
"The <code>#{$i}</code> part is the syntax to combine a variable (<code>i</code>) with text to make a string. When the Sass file is converted to CSS, it looks like this:",
"<blockquote>.col-1 {<br>&nbsp;&nbsp;width: 8.33333%;<br>}<br><br>.col-2 {<br>&nbsp;&nbsp;width: 16.66667%;<br>}<br><br>...<br><br>.col-12 {<br>&nbsp;&nbsp;width: 100%;<br>}</blockquote>",
"This is a powerful way to create a grid layout. Now you have twelve options for column widths available as CSS classes.",
"<hr>",
"Write a <code>@for</code> directive that takes a variable <code>$j</code> that goes from 1 <b>to</b> 6.",
"It should create 5 classes called <code>.text-1</code> to <code>.text-5</code> where each has a <code>font-size</code> set to 10px multiplied by the index."
],
"tests": [
{
"text": "Your code should use the <code>@for</code> directive.",
"testString": "assert(code.match(/@for /g), 'Your code should use the <code>@for</code> directive.');"
},
{
"text": "Your <code>.text-1</code> class should have a <code>font-size</code> of 10px.",
"testString": "assert($('.text-1').css('font-size') == '10px', 'Your <code>.text-1</code> class should have a <code>font-size</code> of 10px.');"
},
{
"text": "Your <code>.text-2</code> class should have a <code>font-size</code> of 20px.",
"testString": "assert($('.text-2').css('font-size') == '20px', 'Your <code>.text-2</code> class should have a <code>font-size</code> of 20px.');"
},
{
"text": "Your <code>.text-3</code> class should have a <code>font-size</code> of 30px.",
"testString": "assert($('.text-3').css('font-size') == '30px', 'Your <code>.text-3</code> class should have a <code>font-size</code> of 30px.');"
},
{
"text": "Your <code>.text-4</code> class should have a <code>font-size</code> of 40px.",
"testString": "assert($('.text-4').css('font-size') == '40px', 'Your <code>.text-4</code> class should have a <code>font-size</code> of 40px.');"
},
{
"text": "Your <code>.text-5</code> class should have a <code>font-size</code> of 50px.",
"testString": "assert($('.text-5').css('font-size') == '50px', 'Your <code>.text-5</code> class should have a <code>font-size</code> of 50px.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" ",
"</style>",
"",
"<p class=\"text-1\">Hello</p>",
"<p class=\"text-2\">Hello</p>",
"<p class=\"text-3\">Hello</p>",
"<p class=\"text-4\">Hello</p>",
"<p class=\"text-5\">Hello</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbf367417b2b2512bba",
"title": "Use @each to Map Over Items in a List",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"The last challenge showed how the <code>@for</code> directive uses a starting and ending value to loop a certain number of times. Sass also offers the <code>@each</code> directive which loops over each item in a list or map.",
"On each iteration, the variable gets assigned to the current value from the list or map.",
"<blockquote>@each $color in blue, red, green {<br>&nbsp;&nbsp;.#{$color}-text {color: $color;}<br>}</blockquote>",
"A map has slightly different syntax. Here's an example:",
"<blockquote>$colors: (color1: blue, color2: red, color3: green);<br><br>@each $key, $color in $colors {<br>&nbsp;&nbsp;.#{$color}-text {color: $color;}<br>}</blockquote>",
"Note that the <code>$key</code> variable is needed to reference the keys in the map. Otherwise, the compiled CSS would have <code>color1</code>, <code>color2</code>... in it.",
"Both of the above code examples are converted into the following CSS:",
"<blockquote>.blue-text {<br>&nbsp;&nbsp;color: blue;<br>}<br><br>.red-text {<br>&nbsp;&nbsp;color: red;<br>}<br><br>.green-text {<br>&nbsp;&nbsp;color: green;<br>}</blockquote>",
"<hr>",
"Write an <code>@each</code> directive that goes through a list: <code>blue, black, red</code> and assigns each variable to a <code>.color-bg</code> class, where the \"color\" part changes for each item.",
"Each class should set the <code>background-color</code> the respective color."
],
"tests": [
{
"text": "Your code should use the <code>@each</code> directive.",
"testString": "assert(code.match(/@each /g), 'Your code should use the <code>@each</code> directive.');"
},
{
"text": "Your <code>.blue-bg</code> class should have a <code>background-color</code> of blue.",
"testString": "assert($('.blue-bg').css('background-color') == 'rgb(0, 0, 255)', 'Your <code>.blue-bg</code> class should have a <code>background-color</code> of blue.');"
},
{
"text": "Your <code>.black-bg</code> class should have a <code>background-color</code> of black.",
"testString": "assert($('.black-bg').css('background-color') == 'rgb(0, 0, 0)', 'Your <code>.black-bg</code> class should have a <code>background-color</code> of black.');"
},
{
"text": "Your <code>.red-bg</code> class should have a <code>background-color</code> of red.",
"testString": "assert($('.red-bg').css('background-color') == 'rgb(255, 0, 0)', 'Your <code>.red-bg</code> class should have a <code>background-color</code> of red.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" ",
" div {",
" height: 200px;",
" width: 200px;",
" }",
"</style>",
"",
"<div class=\"blue-bg\"></div>",
"<div class=\"black-bg\"></div>",
"<div class=\"red-bg\"></div>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbf367417b2b2512bbb",
"title": "Apply a Style Until a Condition is Met with @while",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"The <code>@while</code> directive is an option with similar functionality to the JavaScript <code>while</code> loop. It creates CSS rules until a condition is met.",
"The <code>@for</code> challenge gave an example to create a simple grid system. This can also work with <code>@while</code>.",
"<blockquote>$x: 1;<br>@while $x < 13 {<br>&nbsp;&nbsp;.col-#{$x} { width: 100%/12 * $x;}<br>&nbsp;&nbsp;$x: $x + 1;<br>}</blockquote>",
"First, define a variable <code>$x</code> and set it to 1. Next, use the <code>@while</code> directive to create the grid system <i>while</i> <code>$x</code> is less than 13.",
"After setting the CSS rule for <code>width</code>, <code>$x</code> is incremented by 1 to avoid an infinite loop.",
"<hr>",
"Use <code>@while</code> to create a series of classes with different <code>font-sizes</code>.",
"There should be 10 different classes from <code>text-1</code> to <code>text-10</code>. Then set <code>font-size</code> to 5px multiplied by the current index number. Make sure to avoid an infinite loop!"
],
"tests": [
{
"text": "Your code should use the <code>@while</code> directive.",
"testString": "assert(code.match(/@while /g), 'Your code should use the <code>@while</code> directive.');"
},
{
"text": "Your code should set an index variable to 1 to start.",
"testString": "assert(code.match(/\\$.*:\\s*?1;/gi), 'Your code should set an index variable to 1 to start.');"
},
{
"text": "Your code should increment the counter variable.",
"testString": "assert(code.match(/\\$(.*):\\s*?\\$\\1\\s*?\\+\\s*?1;/gi), 'Your code should increment the counter variable.');"
},
{
"text": "Your <code>.text-1</code> class should have a <code>font-size</code> of 5px.",
"testString": "assert($('.text-1').css('font-size') == '5px', 'Your <code>.text-1</code> class should have a <code>font-size</code> of 5px.');"
},
{
"text": "Your <code>.text-2</code> class should have a <code>font-size</code> of 10px.",
"testString": "assert($('.text-2').css('font-size') == '10px', 'Your <code>.text-2</code> class should have a <code>font-size</code> of 10px.');"
},
{
"text": "Your <code>.text-3</code> class should have a <code>font-size</code> of 15px.",
"testString": "assert($('.text-3').css('font-size') == '15px', 'Your <code>.text-3</code> class should have a <code>font-size</code> of 15px.');"
},
{
"text": "Your <code>.text-4</code> class should have a <code>font-size</code> of 20px.",
"testString": "assert($('.text-4').css('font-size') == '20px', 'Your <code>.text-4</code> class should have a <code>font-size</code> of 20px.');"
},
{
"text": "Your <code>.text-5</code> class should have a <code>font-size</code> of 25px.",
"testString": "assert($('.text-5').css('font-size') == '25px', 'Your <code>.text-5</code> class should have a <code>font-size</code> of 25px.');"
},
{
"text": "Your <code>.text-6</code> class should have a <code>font-size</code> of 30px.",
"testString": "assert($('.text-6').css('font-size') == '30px', 'Your <code>.text-6</code> class should have a <code>font-size</code> of 30px.');"
},
{
"text": "Your <code>.text-7</code> class should have a <code>font-size</code> of 35px.",
"testString": "assert($('.text-7').css('font-size') == '35px', 'Your <code>.text-7</code> class should have a <code>font-size</code> of 35px.');"
},
{
"text": "Your <code>.text-8</code> class should have a <code>font-size</code> of 40px.",
"testString": "assert($('.text-8').css('font-size') == '40px', 'Your <code>.text-8</code> class should have a <code>font-size</code> of 40px.');"
},
{
"text": "Your <code>.text-9</code> class should have a <code>font-size</code> of 45px.",
"testString": "assert($('.text-9').css('font-size') == '45px', 'Your <code>.text-9</code> class should have a <code>font-size</code> of 45px.');"
},
{
"text": "Your <code>.text-10</code> class should have a <code>font-size</code> of 50px.",
"testString": "assert($('.text-10').css('font-size') == '50px', 'Your <code>.text-10</code> class should have a <code>font-size</code> of 50px.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" ",
" ",
" ",
"</style>",
"",
"<p class=\"text-1\">Hello</p>",
"<p class=\"text-2\">Hello</p>",
"<p class=\"text-3\">Hello</p>",
"<p class=\"text-4\">Hello</p>",
"<p class=\"text-5\">Hello</p>",
"<p class=\"text-6\">Hello</p>",
"<p class=\"text-7\">Hello</p>",
"<p class=\"text-8\">Hello</p>",
"<p class=\"text-9\">Hello</p>",
"<p class=\"text-10\">Hello</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7dbf367417b2b2512bbc",
"title": "Split Your Styles into Smaller Chunks with Partials",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"<code>Partials</code> in Sass are separate files that hold segments of CSS code. These are imported and used in other Sass files. This is a great way to group similar code into a module to keep it organized.",
"Names for <code>partials</code> start with the underscore (<code>_</code>) character, which tells Sass it is a small segment of CSS and not to convert it into a CSS file. Also, Sass files end with the <code>.scss</code> file extension. To bring the code in the <code>partial</code> into another Sass file, use the <code>@import</code> directive.",
"For example, if all your <code>mixins</code> are saved in a <code>partial</code> named \"_mixins.scss\", and they are needed in the \"main.scss\" file, this is how to use them in the main file:",
"<blockquote>// In the main.scss file<br><br>@import 'mixins'</blockquote>",
"Note that the underscore is not needed in the <code>import</code> statement - Sass understands it is a <code>partial</code>. Once a <code>partial</code> is imported into a file, all variables, <code>mixins</code>, and other code are available to use.",
"<hr>",
"Write an <code>@import</code> statement to import a <code>partial</code> named <code>_variables.scss</code> into the main.scss file."
],
"tests": [
{
"text": "Your code should use the <code>@import</code> directive, and should not include the underscore in the file name.",
"testString": "assert(code.match(/@import\\s+?('|\")variables\\1/gi), 'Your code should use the <code>@import</code> directive, and should not include the underscore in the file name.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"// The main.scss file",
"",
"",
"",
""
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fa5367417b2b2512bbd",
"title": "Extend One Set of CSS Styles to Another Element",
"required": [
{
"src": "https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.10.9/sass.sync.min.js",
"raw": true
}
],
"description": [
"Sass has a feature called <code>extend</code> that makes it easy to borrow the CSS rules from one element and build upon them in another.",
"For example, the below block of CSS rules style a <code>.panel</code> class. It has a <code>background-color</code>, <code>height</code> and <code>border</code>.",
"<blockquote>.panel{<br>&nbsp;&nbsp;background-color: red;<br>&nbsp;&nbsp;height: 70px;<br>&nbsp;&nbsp;border: 2px solid green;<br>}</blockquote>",
"Now you want another panel called <code>.big-panel</code>. It has the same base properties as <code>.panel</code>, but also needs a <code>width</code> and <code>font-size</code>.",
"It's possible to copy and paste the initial CSS rules from <code>.panel</code>, but the code becomes repetitive as you add more types of panels.",
"The <code>extend</code> directive is a simple way to reuse the rules written for one element, then add more for another:",
"<blockquote>.big-panel{<br>&nbsp;&nbsp;@extend .panel;<br>&nbsp;&nbsp;width: 150px;<br>&nbsp;&nbsp;font-size: 2em;<br>}</blockquote>",
"The <code>.big-panel</code> will have the same properties as <code>.panel</code> in addition to the new styles.",
"<hr>",
"Make a class <code>.info-important</code> that extends <code>.info</code> and also has a <code>background-color</code> set to magenta."
],
"tests": [
{
"text": "Your <code>info-important</code> class should have a <code>background-color</code> set to <code>magenta</code>.",
"testString": "assert(code.match(/\\.info-important\\s*?{[\\s\\S]*background-color\\s*?:\\s*?magenta\\s*?;[\\s\\S]*}/gi), 'Your <code>info-important</code> class should have a <code>background-color</code> set to <code>magenta</code>.');"
},
{
"text": "Your <code>info-important</code> class should use <code>@extend</code> to inherit the styling from the <code>info</code> class.",
"testString": "assert(code.match(/\\.info-important\\s*?{[\\s\\S]*@extend\\s*?.info\\s*?;[\\s\\S]*/gi), 'Your <code>info-important</code> class should use <code>@extend</code> to inherit the styling from the <code>info</code> class.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 0,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<style type='text/sass'>",
" h3{",
" text-align: center;",
" }",
" .info{",
" width: 200px;",
" border: 1px solid black;",
" margin: 0 auto;",
" }",
" ",
" ",
" ",
" ",
"</style>",
"<h3>Posts</h3>",
"<div class=\"info-important\">",
" <p>This is an important post. It should extend the class \".info\" and have its own CSS styles.</p>",
"</div>",
"",
"<div class=\"info\">",
" <p>This is a simple post. It has basic styling and can be extended for other uses.</p>",
"</div>"
],
"head": [],
"tail": []
}
}
}
]
}

View File

@ -0,0 +1,177 @@
{
"name": "Data Visualization Projects",
"order": 3,
"time": "150 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "bd7168d8c242eddfaeb5bd13",
"title": "Visualize Data with a Bar Chart",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/GrZVaM' target='_blank'>https://codepen.io/freeCodeCamp/full/GrZVaM</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <a href='https://github.com/d3/d3/blob/master/API.md#axes-d3-axis' target='_blank'>https://github.com/d3/d3/blob/master/API.md#axes-d3-axis</a>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.",
"<strong>User Story #1:</strong> My chart should have a title with a corresponding <code>id=\"title\"</code>.",
"<strong>User Story #2:</strong> My chart should have a <code>g</code> element x-axis with a corresponding <code>id=\"x-axis\"</code>.",
"<strong>User Story #3:</strong> My chart should have a <code>g</code> element y-axis with a corresponding <code>id=\"y-axis\"</code>.",
"<strong>User Story #4:</strong> Both axes should contain multiple tick labels, each with the corresponding <code>class=\"tick\"</code>.",
"<strong>User Story #5:</strong> My chart should have a <code>rect</code> element for each data point with a corresponding <code>class=\"bar\"</code> displaying the data.",
"<strong>User Story #6:</strong> Each bar should have the properties <code>data-date</code> and <code>data-gdp</code> containing date and GDP values.",
"<strong>User Story #7:</strong> The bar elements' <code>data-date</code> properties should match the order of the provided data.",
"<strong>User Story #8:</strong> The bar elements' <code>data-gdp</code> properties should match the order of the provided data.",
"<strong>User Story #9:</strong> Each bar element's height should accurately represent the data's corresponding GDP.",
"<strong>User Story #10:</strong> The <code>data-date</code> attribute and its corresponding bar element should align with the corresponding value on the x-axis.",
"<strong>User Story #11:</strong> The <code>data-gdp</code> attribute and its corresponding bar element should align with the corresponding value on the y-axis.",
"<strong>User Story #12:</strong> I can mouse over an area and see a tooltip with a corresponding <code>id=\"tooltip\"</code> which displays more information about the area.",
"<strong>User Story #13:</strong> My tooltip should have a <code>data-date</code> property that corresponds to the <code>data-date</code> of the active area.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/GDP-data.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>.",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un gráfico de barras"
}
}
},
{
"id": "bd7178d8c242eddfaeb5bd13",
"title": "Visualize Data with a Scatterplot Graph",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/bgpXyK' target='_blank'>https://codepen.io/freeCodeCamp/full/bgpXyK</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <a href='https://github.com/d3/d3/blob/master/API.md#axes-d3-axis' target='_blank'>https://github.com/d3/d3/blob/master/API.md#axes-d3-axis</a>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.",
"<strong>User Story #1:</strong> I can see a title element that has a corresponding <code>id=\"title\"</code>.",
"<strong>User Story #2:</strong> I can see an x-axis that has a corresponding <code>id=\"x-axis\"</code>.",
"<strong>User Story #3:</strong> I can see a y-axis that has a corresponding <code>id=\"y-axis\"</code>.",
"<strong>User Story #4:</strong> I can see dots, that each have a class of <code>dot</code>, which represent the data being plotted.",
"<strong>User Story #5:</strong> Each dot should have the properties <code>data-xvalue</code> and <code>data-yvalue</code> containing their corresponding x and y values.",
"<strong>User Story #6:</strong> The <code>data-xvalue</code> and <code>data-yvalue</code> of each dot should be within the range of the actual data and in the correct data format. For <code>data-xvalue</code>, integers (full years) or Date objects are acceptable for test evaluation. For <code>data-yvalue</code> (minutes), use Date objects.",
"<strong>User Story #7:</strong> The <code>data-xvalue</code> and its corresponding dot should align with the corresponding point/value on the x-axis.",
"<strong>User Story #8:</strong> The <code>data-yvalue</code> and its corresponding dot should align with the corresponding point/value on the y-axis.",
"<strong>User Story #9:</strong> I can see multiple tick labels on the y-axis with <code>%M:%S</code> time format.",
"<strong>User Story #10:</strong> I can see multiple tick labels on the x-axis that show the year.",
"<strong>User Story #11:</strong> I can see that the range of the x-axis labels are within the range of the actual x-axis data.",
"<strong>User Story #12:</strong> I can see that the range of the y-axis labels are within the range of the actual y-axis data.",
"<strong>User Story #13:</strong> I can see a legend containing descriptive text that has <code>id=\"legend\"</code>.",
"<strong>User Story #14:</strong> I can mouse over an area and see a tooltip with a corresponding <code>id=\"tooltip\"</code> which displays more information about the area.",
"<strong>User Story #15:</strong> My tooltip should have a <code>data-year</code> property that corresponds to the <code>data-xvalue</code> of the active area.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/cyclist-data.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un gráfico de dispersión"
}
}
},
{
"id": "bd7188d8c242eddfaeb5bd13",
"title": "Visualize Data with a Heat Map",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/JEXgeY' target='_blank'>https://codepen.io/freeCodeCamp/full/JEXgeY</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.",
"<strong>User Story #1:</strong> My heat map should have a title with a corresponding <code>id=\"title\"</code>.",
"<strong>User Story #2:</strong> My heat map should have a description with a corresponding <code>id=\"description\"</code>.",
"<strong>User Story #3:</strong> My heat map should have an x-axis with a corresponding <code>id=\"x-axis\"</code>.",
"<strong>User Story #4:</strong> My heat map should have a y-axis with a corresponding <code>id=\"y-axis\"</code>.",
"<strong>User Story #5:</strong> My heat map should have <code>rect</code> elements with a <code>class=\"cell\"</code> that represent the data.",
"<strong>User Story #6:</strong> There should be at least 4 different fill colors used for the cells.",
"<strong>User Story #7:</strong> Each cell will have the properties <code>data-month</code>, <code>data-year</code>, <code>data-temp</code> containing their corresponding month, year, and temperature values.",
"<strong>User Story #8:</strong> The <code>data-month</code>, <code>data-year</code> of each cell should be within the range of the data.",
"<strong>User Story #9:</strong> My heat map should have cells that align with the corresponding month on the y-axis.",
"<strong>User Story #10:</strong> My heat map should have cells that align with the corresponding year on the x-axis.",
"<strong>User Story #11:</strong> My heat map should have multiple tick labels on the y-axis with the full month name.",
"<strong>User Story #12:</strong> My heat map should have multiple tick labels on the x-axis with the years between 1754 and 2015.",
"<strong>User Story #13:</strong> My heat map should have a legend with a corresponding <code>id=\"legend\"</code>.",
"<strong>User Story #14:</strong> My legend should contain <code>rect</code> elements.",
"<strong>User Story #15:</strong> The <code>rect</code> elements in the legend should use at least 4 different fill colors.",
"<strong>User Story #16:</strong> I can mouse over an area and see a tooltip with a corresponding <code>id=\"tooltip\"</code> which displays more information about the area.",
"<strong>User Story #16:</strong> My tooltip should have a <code>data-year</code> property that corresponds to the <code>data-year</code> of the active area.",
"Here is the dataset you will need to complete this project: <code>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/global-temperature.json</code>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"challengeType": 3,
"translations": {
"es": {
"title": "Visualiza datos utilizando un mapa de calor"
}
}
},
{
"id": "587d7fa6367417b2b2512bbf",
"title": "Visualize Data with a Choropleth Map",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/EZKqza' target='_blank'>https://codepen.io/freeCodeCamp/full/EZKqza</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.",
"<strong>User Story #1:</strong> My choropleth should have a title with a corresponding <code>id=\"title\"</code>.",
"<strong>User Story #2:</strong> My choropleth should have a description element with a corresponding <code>id=\"description\"</code>.",
"<strong>User Story #3:</strong> My choropleth should have counties with a corresponding <code>class=\"county\"</code> that represent the data.",
"<strong>User Story #4:</strong> There should be at least 4 different fill colors used for the counties.",
"<strong>User Story #5:</strong> My counties should each have <code>data-fips</code> and <code>data-education</code> properties containing their corresponding fips and education values.",
"<strong>User Story #6:</strong> My choropleth should have a county for each provided data point.",
"<strong>User Story #7:</strong> The counties should have data-fips and data-education values that match the sample data.",
"<strong>User Story #8:</strong> My choropleth should have a legend with a corresponding <code>id=\"legend\"</code>.",
"<strong>User Story #9:</strong> There should be at least 4 different fill colors used for the legend.",
"<strong>User Story #10:</strong> I can mouse over an area and see a tooltip with a corresponding <code>id=\"tooltip\"</code> which displays more information about the area.",
"<strong>User Story #11:</strong> My tooltip should have a <code>data-education</code> property that corresponds to the <code>data-education</code> of the active area.",
"Here are the datasets you will need to complete this project:<br><ul><li><strong>US Education Data: </strong><code>https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/for_user_education.json</code></li><li><strong>US County Data: </strong><code>https://raw.githubusercontent.com/no-stack-dub-sack/testable-projects-fcc/master/src/data/choropleth_map/counties.json</code></li></ul>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"releasedOn": "February 17, 2017",
"challengeType": 3,
"translations": {}
},
{
"id": "587d7fa6367417b2b2512bc0",
"title": "Visualize Data with a Treemap Diagram",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/KaNGNR' target='_blank'>https://codepen.io/freeCodeCamp/full/KaNGNR</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> and get all of the tests to pass. Give it your own personal style.",
"You can use HTML, JavaScript, CSS, and the D3 svg-based visualization library. The tests require axes to be generated using the D3 axis property, which automatically generates ticks along the axis. These ticks are required for passing the D3 tests because their positions are used to determine alignment of graphed elements. You will find information about generating axes at <a href='https://github.com/d3/d3/blob/master/API.md#axes-d3-axis' target='_blank'>https://github.com/d3/d3/blob/master/API.md#axes-d3-axis</a>. Required (non-virtual) DOM elements are queried on the moment of each test. If you use a frontend framework (like Vue for example), the test results may be inaccurate for dynamic content. We hope to accommodate them eventually, but these frameworks are not currently supported for D3 projects.",
"<strong>User Story #1:</strong> My tree map should have a title with a corresponding <code>id=\"title\"</code>.",
"<strong>User Story #2:</strong> My tree map should have a description with a corresponding <code>id=\"description\"</code>.",
"<strong>User Story #3:</strong> My tree map should have <code>rect</code> elements with a corresponding <code>class=\"tile\"</code> that represent the data.",
"<strong>User Story #4:</strong> There should be at least 2 different fill colors used for the tiles.",
"<strong>User Story #5:</strong> Each tile should have the properties <code>data-name</code>, <code>data-category</code>, and <code>data-value</code> containing their corresponding name, category, and value.",
"<strong>User Story #6:</strong> The area of each tile should correspond to the data-value amount: tiles with a larger data-value should have a bigger area.",
"<strong>User Story #7:</strong> My tree map should have a legend with corresponding <code>id=\"legend\"</code>.",
"<strong>User Story #8:</strong> My legend should have <code>rect</code> elements with a corresponding <code>class=\"legend-item\"</code>.",
"<strong>User Story #9:</strong> The <code>rect</code> elements in the legend should use at least 2 different fill colors.",
"<strong>User Story #10:</strong> I can mouse over an area and see a tooltip with a corresponding <code>id=\"tooltip\"</code> which displays more information about the area.",
"<strong>User Story #11:</strong> My tooltip should have a <code>data-value</code> property that corresponds to the <code>data-value</code> of the active area.",
"For this project you can use any of the following datasets:<br><ul><li><strong>Kickstarter Pledges:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/kickstarter-funding-data.json</code></li><li><strong>Movie Sales:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/movie-data.json</code></li><li><strong>Video Game Sales:</strong> <code>https://cdn.rawgit.com/freeCodeCamp/testable-projects-fcc/a80ce8f9/src/data/tree_map/video-game-sales-data.json</code></li></ul>",
"You can build your project by forking <a href='https://codepen.io/freeCodeCamp/pen/MJjpwO' target='_blank'>this CodePen pen</a>. Or you can use this CDN link to run the tests in any environment you like: <code>https://cdn.freecodecamp.org/testable-projects-fcc/v1/bundle.js</code>",
"Once you're done, submit the URL to your working project with all its tests passing.",
"Remember to use the <a href='https://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> method if you get stuck."
],
"tests": [],
"isRequired": true,
"releasedOn": "February 17, 2017",
"challengeType": 3,
"translations": {}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,868 @@
{
"name": "JSON APIs and AJAX",
"order": 2,
"time": "2 hours",
"helpRoom": "Help",
"required": [
{
"link":
"https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css"
}
],
"challenges": [
{
"id": "587d7fad367417b2b2512be1",
"title": "Handle Click Events with JavaScript using the onclick property",
"description": [
"You want your code to execute only once your page has finished loading. For that purpose, you can attach a JavaScript event to the document called <code>DOMContentLoaded</code>. Here's the code that does this:",
"<blockquote>document.addEventListener('DOMContentLoaded',function() {<br><br>});</blockquote>",
"You can implement event handlers that go inside of the <code>DOMContentLoaded</code> function. You can implement an <code>onclick</code> event handler which triggers when the user clicks on the element with id <code>getMessage</code>, by adding the following code:",
"<blockquote>document.getElementById('getMessage').onclick=function(){};</blockquote>",
"<hr>",
"Add a click event handler inside of the <code>DOMContentLoaded</code> function for the element with id of <code>getMessage</code>."
],
"tests": [
{
"text":
"Your code should use the <code>document.getElementById</code> method to select the <code>getMessage</code> element.",
"testString":
"assert(code.match(/document\\.getElementById\\(\\s*?('|\")getMessage\\1\\s*?\\)/g), 'Your code should use the <code>document.getElementById</code> method to select the <code>getMessage</code> element.');"
},
{
"text": "Your code should add an <code>onclick</code> event handler.",
"testString":
"assert(typeof document.getElementById('getMessage').onclick === 'function', 'Your code should add an <code>onclick</code> event handler.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fad367417b2b2512be2",
"title": "Change Text with click Events",
"description": [
"When the click event happens, you can use JavaScript to update an HTML element.",
"For example, when a user clicks the \"Get Message\" button, it changes the text of the element with the class <code>message</code> to say \"Here is the message\".",
"This works by adding the following code within the click event:",
"<code>document.getElementsByClassName('message')[0].textContent=\"Here is the message\";</code>",
"<hr>",
"Add code inside the <code>onclick</code> event handler to change the text inside the <code>message</code> element to say \"Here is the message\"."
],
"tests": [
{
"text":
"Your code should use the <code>document.getElementsByClassName</code> method to select the element with class <code>message</code> and set its <code>textContent</code> to the given string.",
"testString":
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.textContent\\s*?=\\s*?('|\")Here is the message\\2/g), 'Your code should use the <code>document.getElementsByClassName</code> method to select the element with class <code>message</code> and set its <code>textContent</code> to the given string.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" }",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fae367417b2b2512be3",
"title": "Get JSON with the JavaScript XMLHttpRequest Method",
"description": [
"You can also request data from an external source. This is where APIs come into play.",
"Remember that APIs - or Application Programming Interfaces - are tools that computers use to communicate with one another. You'll learn how to update HTML with the data we get from APIs using a technology called AJAX.",
"Most web APIs transfer data in a format called JSON. JSON stands for JavaScript Object Notation.",
"JSON syntax looks very similar to JavaScript object literal notation. JSON has object properties and their current values, sandwiched between a <code>{</code> and a <code>}</code>.",
"These properties and their values are often referred to as \"key-value pairs\".",
"However, JSON transmitted by APIs are sent as <code>bytes</code>, and your application receives it as a <code>string</code>. These can be converted into JavaScript objects, but they are not JavaScript objects by default. The <code>JSON.parse</code> method parses the string and constructs the JavaScript object described by it.",
"You can request the JSON from freeCodeCamp's Cat Photo API. Here's the code you can put in your click event to do this:",
"<blockquote>req=new XMLHttpRequest();<br>req.open(\"GET\",'/json/cats.json',true);<br>req.send();<br>req.onload=function(){<br>&nbsp;&nbsp;json=JSON.parse(req.responseText);<br>&nbsp;&nbsp;document.getElementsByClassName('message')[0].innerHTML=JSON.stringify(json);<br>};</blockquote>",
"Here's a review of what each piece is doing. The JavaScript <code>XMLHttpRequest</code> object has a number of properties and methods that are used to transfer data. First, an instance of the <code>XMLHttpRequest</code> object is created and saved in the <code>req</code> variable.",
"Next, the <code>open</code> method initializes a request - this example is requesting data from an API, therefore is a \"GET\" request. The second argument for <code>open</code> is the URL of the API you are requesting data from. The third argument is a Boolean value where <code>true</code> makes it an asynchronous request.",
"The <code>send</code> method sends the request. Finally, the <code>onload</code> event handler parses the returned data and applies the <code>JSON.stringify</code> method to convert the JavaScript object into a string. This string is then inserted as the message text.",
"<hr>",
"Update the code to create and send a \"GET\" request to the freeCodeCamp Cat Photo API. Then click the \"Get Message\" button. Your AJAX function will replace the \"The message will go here\" text with the raw JSON output from the API."
],
"tests": [
{
"text": "Your code should create a new <code>XMLHttpRequest</code>.",
"testString":
"assert(code.match(/new\\s+?XMLHttpRequest\\(\\s*?\\)/g), 'Your code should create a new <code>XMLHttpRequest</code>.');"
},
{
"text":
"Your code should use the <code>open</code> method to initialize a \"GET\" request to the freeCodeCamp Cat Photo API.",
"testString":
"assert(code.match(/\\.open\\(\\s*?('|\")GET\\1\\s*?,\\s*?('|\")\\/json\\/cats\\.json\\2\\s*?,\\s*?true\\s*?\\)/g), 'Your code should use the <code>open</code> method to initialize a \"GET\" request to the freeCodeCamp Cat Photo API.');"
},
{
"text":
"Your code should use the <code>send</code> method to send the request.",
"testString":
"assert(code.match(/\\.send\\(\\s*\\)/g), 'Your code should use the <code>send</code> method to send the request.');"
},
{
"text":
"Your code should have an <code>onload</code> event handler set to a function.",
"testString":
"assert(code.match(/\\.onload\\s*=\\s*function\\(\\s*?\\)\\s*?{/g), 'Your code should have an <code>onload</code> event handler set to a function.');"
},
{
"text":
"Your code should use the <code>JSON.parse</code> method to parse the <code>responseText</code>.",
"testString":
"assert(code.match(/JSON\\.parse\\(.*\\.responseText\\)/g), 'Your code should use the <code>JSON.parse</code> method to parse the <code>responseText</code>.');"
},
{
"text":
"Your code should get the element with class <code>message</code> and change its inner HTML to the string of JSON data.",
"testString":
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.innerHTML\\s*?=\\s*?JSON\\.stringify\\(.+?\\)/g), 'Your code should get the element with class <code>message</code> and change its inner HTML to the string of JSON data.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fae367417b2b2512be4",
"title": "Access the JSON Data from an API",
"description": [
"In the previous challenge, you saw how to get JSON data from the freeCodeCamp Cat Photo API.",
"Now you'll take a closer look at the returned data to better understand the JSON format. Recall some notation in JavaScript:",
"<blockquote>[ ] -> Square brackets represent an array<br>{ } -> Curly brackets represent an object<br>\" \" -> Double quotes represent a string. They are also used for key names in JSON</blockquote>",
"Understanding the structure of the data that an API returns is important because it influences how you retrieve the values you need.",
"On the right, click the \"Get Message\" button to load the freeCodeCamp Cat Photo API JSON into the HTML.",
"The first and last character you see in the JSON data are square brackets <code>[ ]</code>. This means that the returned data is an array. The second character in the JSON data is a curly <code>{</code> bracket, which starts an object. Looking closely, you can see that there are three separate objects. The JSON data is an array of three objects, where each object contains information about a cat photo.",
"You learned earlier that objects contain \"key-value pairs\" that are separated by commas. In the Cat Photo example, the first object has <code>\"id\":0</code> where \"id\" is a key and 0 is its corresponding value. Similarly, there are keys for \"imageLink\", \"altText\", and \"codeNames\". Each cat photo object has these same keys, but with different values.",
"Another interesting \"key-value pair\" in the first object is <code>\"codeNames\":[\"Juggernaut\",\"Mrs. Wallace\",\"ButterCup\"]</code>. Here \"codeNames\" is the key and its value is an array of three strings. It's possible to have arrays of objects as well as a key with an array as a value.",
"Remember how to access data in arrays and objects. Arrays use bracket notation to access a specific index of an item. Objects use either bracket or dot notation to access the value of a given property. Here's an example that prints the \"altText\" of the first cat photo - note that the parsed JSON data in the editor is saved in a variable called <code>json</code>:",
"<blockquote>console.log(json[0].altText);<br>// Prints \"A white cat wearing a green helmet shaped melon on its head.\"</blockquote>",
"<hr>",
"For the cat with the \"id\" of 2, print to the console the second value in the <code>codeNames</code> array. You should use bracket and dot notation on the object (which is saved in the variable <code>json</code>) to access the value."
],
"tests": [
{
"text":
"Your code should use bracket and dot notation to access the proper code name, and print \"Loki\" to the console.",
"testString":
"assert(code.match(/(?:json\\[2\\]\\.codeNames\\[1\\]|json\\[2\\]\\[('|\")codeNames\\1\\]\\[1\\])/g), 'Your code should use bracket and dot notation to access the proper code name, and print \"Loki\" to the console.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" document.getElementsByClassName('message')[0].innerHTML=JSON.stringify(json);",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fae367417b2b2512be5",
"title": "Convert JSON Data to HTML",
"description": [
"Now that you're getting data from a JSON API, you can display it in the HTML.",
"You can use a <code>forEach</code> method to loop through the data since the cat photo objects are held in an array. As you get to each item, you can modify the HTML elements.",
"First, declare an html variable with <code>var html = \"\";</code>.",
"Then, loop through the JSON, adding HTML to the variable that wraps the key names in <code>strong</code> tags, followed by the value. When the loop is finished, you render it.",
"Here's the code that does this:",
"<blockquote>json.forEach(function(val) {</br>&nbsp;&nbsp;var keys = Object.keys(val);</br>&nbsp;&nbsp;html += \"&lt;div class = 'cat'&gt;\";</br>&nbsp;&nbsp;keys.forEach(function(key) {</br>&nbsp;&nbsp;&nbsp;&nbsp;html += \"&lt;strong&gt;\" + key + \"&lt;/strong&gt;: \" + val[key] + \"&lt;br&gt;\";</br>&nbsp;&nbsp;});</br>&nbsp;&nbsp;html += \"&lt;/div&gt;&lt;br&gt;\";</br>});</blockquote>",
"<hr>",
"Add a <code>forEach</code> method to loop over the JSON data and create the HTML elements to display it.",
"Here is some example JSON",
"<blockquote>[</br>&nbsp;&nbsp;{</br>&nbsp;&nbsp;&nbsp;&nbsp;\"id\":0,</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"imageLink\":\"https://s3.amazonaws.com/freecodecamp/funny-cat.jpg\",</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"altText\":\"A white cat wearing a green helmet shaped melon on its head. \",</br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;\"codeNames\":[ \"Juggernaut\", \"Mrs. Wallace\", \"Buttercup\"</br>&nbsp;&nbsp;&nbsp;&nbsp;]</br>&nbsp;&nbsp;}</br>]</blockquote>"
],
"tests": [
{
"text":
"Your code should store the data in the <code>html</code> variable",
"testString":
"assert(code.match(/html\\s+?(\\+=|=\\shtml\\s\\+)/g), 'Your code should store the data in the <code>html</code> variable');"
},
{
"text":
"Your code should use a <code>forEach</code> method to loop over the JSON data from the API.",
"testString":
"assert(code.match(/json\\.forEach/g), 'Your code should use a <code>forEach</code> method to loop over the JSON data from the API.');"
},
{
"text":
"Your code should wrap the key names in <code>strong</code> tags.",
"testString":
"assert(code.match(/<strong>.+<\\/strong>/g), 'Your code should wrap the key names in <code>strong</code> tags.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" // Add your code below this line",
" ",
" ",
" ",
" // Add your code above this line",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fae367417b2b2512be6",
"title": "Render Images from Data Sources",
"description": [
"The last few challenges showed that each object in the JSON array contains an <code>imageLink</code> key with a value that is the URL of a cat's image.",
"When you're looping through these objects, you can use this <code>imageLink</code> property to display this image in an <code>img</code> element.",
"Here's the code that does this:",
"<code>html += \"&lt;img src = '\" + val.imageLink + \"' \" + \"alt='\" + val.altText + \"'&gt;\";</code>",
"<hr>",
"Add code to use the <code>imageLink</code> and <code>altText</code> properties in an <code>img</code> tag."
],
"tests": [
{
"text":
"You should use the <code>imageLink</code> property to display the images.",
"testString":
"assert(code.match(/val\\.imageLink/g), 'You should use the <code>imageLink</code> property to display the images.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" json.forEach(function(val) {",
" html += \"<div class = 'cat'>\";",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" html += \"</div><br>\";",
" });",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7fae367417b2b2512be7",
"title": "Pre-filter JSON to Get the Data You Need",
"description": [
"If you don't want to render every cat photo you get from the freeCodeCamp Cat Photo API, you can pre-filter the JSON before looping through it.",
"Given that the JSON data is stored in an array, you can use the <code>filter</code> method to filter out the cat whose \"id\" key has a value of 1.",
"Here's the code to do this:",
"<blockquote>json = json.filter(function(val) {<br>&nbsp;&nbsp;return (val.id !== 1);<br>});</blockquote>",
"<hr>",
"Add code to <code>filter</code> the json data to remove the cat with the \"id\" value of 1."
],
"tests": [
{
"text": "Your code should use the <code>filter</code> method.",
"testString":
"assert(code.match(/json\\.filter/g), 'Your code should use the <code>filter</code> method.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('getMessage').onclick=function(){",
" req=new XMLHttpRequest();",
" req.open(\"GET\",'/json/cats.json',true);",
" req.send();",
" req.onload=function(){",
" json=JSON.parse(req.responseText);",
" var html = \"\";",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" json.forEach(function(val) {",
" html += \"<div class = 'cat'>\"",
" ",
" html += \"<img src = '\" + val.imageLink + \"' \" + \"alt='\" + val.altText + \"'>\"",
" ",
" html += \"</div>\"",
" });",
" document.getElementsByClassName('message')[0].innerHTML=html;",
" };",
" }; ",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Photo Finder</h1> ",
"<p class=\"message box\">",
" The message will go here",
"</p>",
"<p>",
" <button id=\"getMessage\">",
" Get Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7faf367417b2b2512be8",
"title": "Get Geolocation Data to Find A User's GPS Coordinates",
"description": [
"Another cool thing you can do is access your user's current location. Every browser has a built in navigator that can give you this information.",
"The navigator will get the user's current longitude and latitude.",
"You will see a prompt to allow or block this site from knowing your current location. The challenge can be completed either way, as long as the code is correct.",
"By selecting allow, you will see the text on the output phone change to your latitude and longitude.",
"Here's code that does this:",
"<blockquote>if (navigator.geolocation){<br>&nbsp;&nbsp;navigator.geolocation.getCurrentPosition(function(position) {<br>&nbsp;&nbsp;&nbsp;&nbsp;document.getElementById('data').innerHTML=\"latitude: \"+ position.coords.latitude + \"&lt;br&gt;longitude: \" + position.coords.longitude;<br>&nbsp;&nbsp;});<br>}</blockquote>",
"First, it checks if the <code>navigator.geolocation</code> object exists. If it does, the <code>getCurrentPosition</code> method on that object is called, which initiates an asynchronous request for the user's position. If the request is successful, the callback function in the method runs. This function accesses the <code>position</code> object's values for latitude and longitude using dot notation and updates the HTML.",
"<hr>",
"Add the example code inside the <code>script</code> tags to check a user's current location and insert it into the HTML."
],
"tests": [
{
"text":
"Your code should use <code>navigator.geolocation</code> to access the user&#39;s current location.",
"testString":
"assert(code.match(/navigator\\.geolocation\\.getCurrentPosition/g), 'Your code should use <code>navigator.geolocation</code> to access the user&#39;s current location.');"
},
{
"text":
"Your code should use <code>position.coords.latitude</code> to display the user&#39;s latitudinal location.",
"testString":
"assert(code.match(/position\\.coords\\.latitude/g), 'Your code should use <code>position.coords.latitude</code> to display the user&#39;s latitudinal location.');"
},
{
"text":
"Your code should use <code>position.coords.longitude</code> to display the user&#39;s longitudinal location.",
"testString":
"assert(code.match(/position\\.coords\\.longitude/g), 'Your code should use <code>position.coords.longitude</code> to display the user&#39;s longitudinal location.');"
},
{
"text":
"You should display the user&#39;s position within the <code>data</code> div element.",
"testString":
"assert(code.match(/document\\.getElementById\\(\\s*?('|\")data\\1\\s*?\\)\\.innerHTML/g), 'You should display the user&#39;s position within the <code>data</code> div element.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
"</script>",
"<h4>You are here:</h4>",
"<div id=\"data\">",
"",
"</div>"
],
"head": [],
"tail": []
}
}
},
{
"id": "587d7faf367417b2b2512be9",
"title": "Post Data with the JavaScript XMLHttpRequest Method",
"description": [
"In the previous examples, you received data from an external resource. You can also send data to an external resource, as long as that resource supports AJAX requests and you know the URL.",
"JavaScript's <code>XMLHttpRequest</code> method is also used to post data to a server. Here's an example:",
"<blockquote>req=new XMLHttpRequest();<br>req.open(\"POST\",url,true);<br>req.setRequestHeader('Content-Type','text/plain');<br>req.onreadystatechange=function(){<br>&nbsp;&nbsp;if(req.readyState==4 && req.status==200){<br>&nbsp;&nbsp;&nbsp;&nbsp;document.getElementsByClassName('message')[0].innerHTML=req.responseText;<br>&nbsp;&nbsp;}<br>};<br>req.send(userName);</blockquote>",
"You've seen several of these methods before. Here the <code>open</code> method initializes the request as a \"POST\" to the given URL of the external resource, and uses the <code>true</code> Boolean to make it asynchronous.",
"The <code>setRequestHeader</code> method sets the value of an HTTP request header, which contains information about the sender and the request. It must be called after the <code>open</code> method, but before the <code>send</code> method. The two parameters are the name of the header and the value to set as the body of that header.",
"Next, the <code>onreadystatechange</code> event listener handles a change in the state of the request. A <code>readyState</code> of 4 means the operation is complete, and a <code>status</code> of 200 means it was a successful request. The document's HTML can be updated.",
"Finally, the <code>send</code> method sends the request with the <code>userName</code> value, which was given by the user in the <code>input</code> field.",
"<hr>",
"Update the code to create and send a \"POST\" request. Then enter your name in input box and click \"Send Message\". Your AJAX function will replace \"Reply from Server will be here.\" with the reply of the server. In this case, it is your name appended with \" loves cats\"."
],
"tests": [
{
"text": "Your code should create a new <code>XMLHttpRequest</code>.",
"testString":
"assert(code.match(/new\\s+?XMLHttpRequest\\(\\s*?\\)/g), 'Your code should create a new <code>XMLHttpRequest</code>.');"
},
{
"text":
"Your code should use the <code>open</code> method to initialize a \"POST\" request to the server.",
"testString":
"assert(code.match(/\\.open\\(\\s*?('|\")POST\\1\\s*?,\\s*?url\\s*?,\\s*?true\\s*?\\)/g), 'Your code should use the <code>open</code> method to initialize a \"POST\" request to the server.');"
},
{
"text":
"Your code should use the <code>setRequestHeader</code> method.",
"testString":
"assert(code.match(/\\.setRequestHeader\\(\\s*?('|\")Content-Type\\1\\s*?,\\s*?('|\")text\\/plain\\2\\s*?\\)/g), 'Your code should use the <code>setRequestHeader</code> method.');"
},
{
"text":
"Your code should have an <code>onreadystatechange</code> event handler set to a function.",
"testString":
"assert(code.match(/\\.onreadystatechange\\s*?=/g), 'Your code should have an <code>onreadystatechange</code> event handler set to a function.');"
},
{
"text":
"Your code should get the element with class <code>message</code> and change its inner HTML to the <code>responseText</code>.",
"testString":
"assert(code.match(/document\\.getElementsByClassName\\(\\s*?('|\")message\\1\\s*?\\)\\[0\\]\\.innerHTML\\s*?=\\s*?.+?\\.responseText/g), 'Your code should get the element with class <code>message</code> and change its inner HTML to the <code>responseText</code>.');"
},
{
"text": "Your code should use the <code>send</code> method.",
"testString":
"assert(code.match(/\\.send\\(\\s*?userName\\s*?\\)/g), 'Your code should use the <code>send</code> method.');"
}
],
"solutions": [],
"hints": [],
"releasedOn": "Feb 17, 2017",
"challengeType": 6,
"translations": {},
"files": {
"indexhtml": {
"key": "indexhtml",
"ext": "html",
"name": "index",
"contents": [
"<script>",
" document.addEventListener('DOMContentLoaded',function(){",
" document.getElementById('sendMessage').onclick=function(){",
" ",
" var userName=document.getElementById('name').value;",
" // Add your code below this line",
" ",
" ",
" // Add your code above this line",
" };",
" });",
"</script>",
"<style>",
" body {",
" text-align: center;",
" font-family: \"Helvetica\", sans-serif;",
" }",
" h1 {",
" font-size: 2em;",
" font-weight: bold;",
" }",
" .box {",
" border-radius: 5px;",
" background-color: #eee;",
" padding: 20px 5px;",
" }",
" button {",
" color: white;",
" background-color: #4791d0;",
" border-radius: 5px;",
" border: 1px solid #4791d0;",
" padding: 5px 10px 8px 10px;",
" }",
" button:hover {",
" background-color: #0F5897;",
" border: 1px solid #0F5897;",
" }",
"</style>",
"<h1>Cat Friends</h1> ",
"<p class=\"message box\">",
" Reply from Server will be here",
"</p>",
"<p>",
" <label for=\"name\">Your name:",
" <input type=\"text\" id=\"name\"/>",
" </label>",
" <button id=\"sendMessage\">",
" Send Message",
" </button>",
"</p>"
],
"head": [],
"tail": []
}
}
}
]
}

View File

@ -0,0 +1,203 @@
{
"name": "APIs and Microservices Projects",
"order": 4,
"time": "150 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "bd7158d8c443edefaeb5bdef",
"title": "Timestamp Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://curse-arrow.glitch.me/' target='_blank'>https://curse-arrow.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-timestamp/' target='_blank'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-timestamp/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text":
"It should handle a valid date, and return the correct unix timestamp",
"testString":
"getUserInput => $.get(getUserInput('url') + '/api/timestamp/2016-12-25').then(data => { assert.equal(data.unix, 1482624000000, 'Should be a valid unix timestamp'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"It should handle a valid date, and return the correct UTC string",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/api/timestamp/2016-12-25').then(data => { assert.equal(data.utc, 'Sun, 25 Dec 2016 00:00:00 GMT', 'Should be a valid UTC date string'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"It should handle a valid unix date, and return the correct unix timestamp",
"testString":
"getUserInput => $.get(getUserInput('url') + '/api/timestamp/1482624000000').then(data => { assert.equal(data.unix, 1482624000000) ; }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"It should return the expected error message for an invalid date",
"testString":
"getUserInput => $.get(getUserInput('url') + '/api/timestamp/this-is-not-a-date').then(data => { assert.equal(data.error.toLowerCase(), 'invalid date');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"It should handle an empty date parameter, and return the current time in unix format",
"testString":
"getUserInput => $.get(getUserInput('url') + '/api/timestamp').then(data => { var now = Date.now(); assert.approximately(data.unix, now, 20000) ;}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"It should handle an empty date parameter, and return the current time in UTC format",
"testString":
"getUserInput => $.get(getUserInput('url') + '/api/timestamp').then(data => { var now = Date.now(); var serverTime = (new Date(data.utc)).getTime(); assert.approximately(serverTime, now, 20000) ;}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio de Marca Temporal"
}
}
},
{
"id": "bd7158d8c443edefaeb5bdff",
"title": "Request Header Parser Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://dandelion-roar.glitch.me/' target='_blank'>https://dandelion-roar.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-headerparser/' target='_blank'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-headerparser/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text":
"I can get the IP address, language and operating system for my browser.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio para analizar el encabezado de una petición"
}
}
},
{
"id": "bd7158d8c443edefaeb5bd0e",
"title": "URL Shortener Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://thread-paper.glitch.me/' target='_blank'>https://thread-paper.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-urlshortener/' target='_blank'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-urlshortener/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text":
"I can pass a URL as a parameter and I will receive a shortened URL in the JSON response.",
"testString": ""
},
{
"text":
"If I pass an invalid URL that doesn't follow the valid http://www.example.com format, the JSON response will contain an error instead.",
"testString": ""
},
{
"text":
"When I visit that shortened URL, it will redirect me to my original link.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio para acortar URLs"
}
}
},
{
"id": "5a8b073d06fa14fcfde687aa",
"title": "Exercise Tracker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://fuschia-custard.glitch.me/' target='_blank'>https://fuschia-custard.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-exercisetracker/' target='_blank'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-exercisetracker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text":
"I can create a user by posting form data username to /api/exercise/new-user and returned will be an object with username and <code>_id</code>.",
"testString": ""
},
{
"text":
"I can get an array of all users by getting api/exercise/users with the same info as when creating a user.",
"testString": ""
},
{
"text":
"I can add an exercise to any user by posting form data userId(_id), description, duration, and optionally date to /api/exercise/add. If no date supplied it will use current date. App will return the user object with the exercise fields added.",
"testString": ""
},
{
"text":
"I can retrieve a full exercise log of any user by getting /api/exercise/log with a parameter of userId(_id). App will return the user object with added array log and count (total exercise count).",
"testString": ""
},
{
"text":
"I can retrieve part of the log of any user by also passing along optional parameters of from & to or limit. (Date format yyyy-mm-dd, limit = int)",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "February 17, 2017",
"translations": {
"es": {
"title": "Capa de abstracción para buscar imágenes"
}
}
},
{
"id": "bd7158d8c443edefaeb5bd0f",
"title": "File Metadata Microservice",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://purple-paladin.glitch.me/' target='_blank'>https://purple-paladin.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-filemetadata/' target='_blank'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-filemetadata/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "I can submit a FormData object that includes a file upload.",
"testString": ""
},
{
"text":
"When I submit something, I will receive the file size in bytes within the JSON response.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 1, 2016",
"translations": {
"es": {
"title": "Microservicio de metadatos de archivos"
}
}
}
]
}

View File

@ -0,0 +1,275 @@
{
"name": "Basic Node and Express",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb0367417b2b2512bed",
"title": "Meet the Node console",
"description": [
"During the development process, it is important to be able to check whats going on in your code. Node is just a JavaScript environment. Like client side JavaScript, you can use the console to display useful debug information. On your local machine, you would see the console output in a terminal. On Glitch you can open the logs in the lower part of the screen. You can toggle the log panel with the button Logs (top-left, under the app name).",
"To get started, just print the classic \"Hello World\" in the console. We recommend to keep the log panel open while working at these challenges. Reading the logs you can be aware of the nature of the errors that may occur."
],
"tests": [
{
"text": "<code>\"Hello World\"</code> should be in the console",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/hello-console').then(data => { assert.isTrue(data.passed, '\"Hello World\" is not in the server console'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bee",
"title": "Start a Working Express Server",
"description": [
"In the first two lines of the file myApp.js you can see how its easy to create an Express app object. This object has several methods, and we will learn many of them in these challenges. One fundamental method is <code>app.listen(port)</code>. It tells your server to listen on a given port, putting it in running state. You can see it at the bottom of the file. It is inside comments because for testing reasons we need the app to be running in background. All the code that you may want to add goes between these two fundamental parts. Glitch stores the port number in the environment variable <code>process.env.PORT</code>. Its value is <code>3000</code>.",
"Lets serve our first string! In Express, routes takes the following structure: <code>app.METHOD(PATH, HANDLER)</code>. METHOD is an http method in lowercase. PATH is a relative path on the server (it can be a string, or even a regular expression). HANDLER is a function that Express calls when the route is matched.",
"Handlers take the form <code>function(req, res) {...}</code>, where req is the request object, and res is the response object. For example, the handler",
"<blockquote>function(req, res) {<br> res.send('Response String');<br>}</blockquote>",
"will serve the string 'Response String'.",
"Use the <code>app.get()</code> method to serve the string Hello Express, to GET requests matching the / root path. Be sure that your code works by looking at the logs, then see the results in your browser, clicking the button Show Live in the Glitch UI."
],
"tests": [
{
"text": "Your app should serve the string 'Hello Express'",
"testString": "getUserInput => $.get(getUserInput('url')).then(data => { assert.equal(data, 'Hello Express', 'Your app does not serve the text \"Hello Express\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bef",
"title": "Serve an HTML File",
"description": [
"We can respond with a file using the method <code>res.sendFile(path)</code>.",
"You can put it inside the <code>app.get('/', ...)</code> route handler. Behind the scenes this method will set the appropriate headers to instruct your browser on how to handle the file you want to send, according to its type. Then it will read and send the file. This method needs an absolute file path. We recommend you to use the Node global variable <code>__dirname</code> to calculate the path.",
"e.g. <code>absolutePath = __dirname + relativePath/file.ext</code>.",
"The file to send is <code>/views/index.html</code>. Try to Show Live your app, you should see a big HTML heading (and a form that we will use later…), with no style applied.",
"Note: You can edit the solution of the previous challenge, or create a new one. If you create a new solution, keep in mind that Express evaluates the routes from top to bottom. It executes the handler for the first match. You have to comment out the preceding solution, or the server will keep responding with a string."
],
"tests": [
{
"text": "Your app should serve the file views/index.html",
"testString": "getUserInput => $.get(getUserInput('url')).then(data => { assert.match(data, /<h1>.*<\\/h1>/, 'Your app does not serve the expected HTML'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb0367417b2b2512bf0",
"title": "Serve Static Assets",
"description": [
"An HTML server usually has one or more directories that are accessible by the user. You can place there the static assets needed by your application (stylesheets, scripts, images). In Express you can put in place this functionality using the middleware <code>express.static(path)</code>, where the parameter is the absolute path of the folder containing the assets. If you dont know what a middleware is, dont worry. Well discuss about it later in details. Basically middlewares are functions that intercept route handlers, adding some kind of information. A middleware needs to be mounted using the method <code>app.use(path, middlewareFunction)</code>. The first path argument is optional. If you dont pass it, the middleware will be executed for all the requests.",
"Mount the <code>express.static()</code> middleware for all the requests with <code>app.use()</code>. The absolute path to the assets folder is <code>__dirname + /public</code>.",
"Now your app should be able to serve a CSS stylesheet. From outside the public folder will appear mounted to the root directory. Your front-page should look a little better now!"
],
"tests": [
{
"text": "Your app should serve asset files from the <code>/public</code> directory",
"testString": "getUserInput => $.get(getUserInput('url') + '/style.css').then(data => { assert.match(data, /body\\s*\\{[^\\}]*\\}/, 'Your app does not serve static assets'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf1",
"title": "Serve JSON on a Specific Route",
"description": [
"While an HTML server serves (you guessed it!) HTML, an API serves data. A <dfn>REST</dfn> (REpresentational State Transfer) API allows data exchange in a simple way, without the need for clients to know any detail about the server. The client only needs to know where the resource is (the URL), and the action it wants to perform on it (the verb). The GET verb is used when you are fetching some information, without modifying anything. These days, the preferred data format for moving information around the web is JSON. Simply put, JSON is a convenient way to represent a JavaScript object as a string, so it can be easily transmitted.",
"Let's create a simple API by creating a route that responds with JSON at the path <code>/json</code>. You can do it as usual, with the <code>app.get()</code> method. Inside the route handler use the method <code>res.json()</code>, passing in an object as an argument. This method closes the request-response loop, returning the data. Behind the scenes it converts a valid JavaScript object into a string, then sets the appropriate headers to tell your browser that you are serving JSON, and sends the data back. A valid object has the usual structure <code>{key: data}</code>. Data can ba a number, a string, a nested object or an array. Data can also be a variable or the result of a function call; in which case it will be evaluated before being converted into a string.",
"Serve the object <code>{\"message\": \"Hello json\"}</code> as a response in JSON format, to the GET requests to the route <code>/json</code>. Then point your browser to your-app-url/json, you should see the message on the screen."
],
"tests": [
{
"text": "The endpoint <code>/json</code> should serve the json object <code>{\"message\": \"Hello json\"}</code>",
"testString": "getUserInput => $.get(getUserInput('url') + '/json').then(data => { assert.equal(data.message, 'Hello json', 'The \\'/json\\' endpoint does not serve the right data'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf2",
"title": "Use the .env File",
"description": [
"The <code>.env</code> file is a hidden file that is used to pass environment variables to your application. This file is secret, no one but you can access it, and it can be used to store data that you want to keep private or hidden. For example, you can store API keys from external services or your database URI. You can also use it to store configuration options. By setting configuration options, you can change the behavior of your application, without the need to rewrite some code.",
"The environment variables are accessible from the app as <code>process.env.VAR_NAME</code>. The <code>process.env</code> object is a global Node object, and variables are passed as strings. By convention, the variable names are all uppercase, with words separated by an underscore. The <code>.env</code> is a shell file, so you dont need to wrap names or values in quotes. It is also important to note that there cannot be space around the equals sign when you are assigning values to your variables, e.g. <code>VAR_NAME=value</code>. Usually, you will put each variable definition on a separate line.",
"Let's add an environment variable as a configuration option. Store the variable <code>MESSAGE_STYLE=uppercase</code> in the <code>.env</code> file. Then tell the GET <code>/json</code> route handler that you created in the last challenge to transform the response objects message to uppercase if <code>process.env.MESSAGE_STYLE</code> equals <code>uppercase</code>. The response object should become <code>{\"message\": \"HELLO JSON\"}</code>."
],
"tests": [
{
"text": "The response of the endpoint <code>/json</code> should change according to the environment variable <code>MESSAGE_STYLE</code>",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/use-env-vars').then(data => { assert.isTrue(data.passed, 'The response of \"/json\" does not change according to MESSAGE_STYLE'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf3",
"title": "Implement a Root-Level Request Logger Middleware",
"description": [
"Before we introduced the <code>express.static()</code> middleware function. Now its time to see what middleware is, in more detail. Middleware functions are functions that take 3 arguments: the request object, the response object, and the next function in the applications request-response cycle. These functions execute some code that can have side effects on the app, and usually add informations to the request or response objects. They can also end the cycle sending the response, when some condition is met. If they dont send the response, when they are done they start the execution of the next function in the stack. This is triggered calling the 3rd argument <code>next()</code>. More information in the <a href='http://expressjs.com/en/guide/using-middleware.html' target='_blank'>express documentation</a>.",
"Look at the following example :",
"<blockquote>function(req, res, next) {<br> console.log(\"I'm a middleware...\");<br> next();<br>}</blockquote>",
"Lets suppose we mounted this function on a route. When a request matches the route, it displays the string “Im a middleware…”. Then it executes the next function in the stack.",
"In this exercise we are going to build a root-level middleware. As we have seen in challenge 4, to mount a middleware function at root level we can use the method <code>app.use(&lt;mware-function&gt;)</code>. In this case the function will be executed for all the requests, but you can also set more specific conditions. For example, if you want a function to be executed only for POST requests, you could use <code>app.post(&lt;mware-function&gt;)</code>. Analogous methods exist for all the http verbs (GET, DELETE, PUT, …).",
"Build a simple logger. For every request, it should log in the console a string taking the following format: <code>method path - ip</code>. An example would look like: <code>GET /json - ::ffff:127.0.0.1</code>. Note that there is a space between <code>method</code> and <code>path</code> and that the dash separating <code>path</code> and <code>ip</code> is surrounded by a space on either side. You can get the request method (http verb), the relative route path, and the callers ip from the request object, using <code>req.method</code>, <code>req.path</code> and <code>req.ip</code>. Remember to call <code>next()</code> when you are done, or your server will be stuck forever. Be sure to have the Logs opened, and see what happens when some request arrives…",
"Hint: Express evaluates functions in the order they appear in the code. This is true for middleware too. If you want it to work for all the routes, it should be mounted before them."
],
"tests": [
{
"text": "Root level logger middleware should be active",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/root-middleware-logger').then(data => { assert.isTrue(data.passed, 'root-level logger is not working as expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb1367417b2b2512bf4",
"title": "Chain Middleware to Create a Time Server",
"description": [
"Middleware can be mounted at a specific route using <code>app.METHOD(path, middlewareFunction)</code>. Middleware can also be chained inside route definition.",
"Look at the following example:",
"<blockquote>app.get('/user', function(req, res, next) {<br> req.user = getTheUserSync(); // Hypothetical synchronous operation<br> next();<br>}, function(req, res) {<br> res.send(req.user);<br>})</blockquote>",
"This approach is useful to split the server operations into smaller units. That leads to a better app structure, and the possibility to reuse code in different places. This approach can also be used to perform some validation on the data. At each point of the middleware stack you can block the execution of the current chain and pass control to functions specifically designed to handle errors. Or you can pass control to the next matching route, to handle special cases. We will see how in the advanced Express section.",
"In the route <code>app.get('/now', ...)</code> chain a middleware function and the final handler. In the middleware function you should add the current time to the request object in the <code>req.time</code> key. You can use <code>new Date().toString()</code>. In the handler, respond with a JSON object, taking the structure <code>{time: req.time}</code>.",
"Hint: The test will not pass if you dont chain the middleware. If you mount the function somewhere else, the test will fail, even if the output result is correct."
],
"tests": [
{
"text": "The /now endpoint should have mounted middleware",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/chain-middleware-time').then(data => { assert.equal(data.stackLength, 2, '\"/now\" route has no mounted middleware'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "The /now endpoint should return a time that is +/- 20 secs from now",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/chain-middleware-time').then(data => { var now = new Date(); assert.isAtMost(Math.abs(new Date(data.time) - now), 20000, 'the returned time is not between +- 20 secs from now'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf5",
"title": "Get Route Parameter Input from the Client",
"description": [
"When building an API, we have to allow users to communicate to us what they want to get from our service. For example, if the client is requesting information about a user stored in the database, they need a way to let us know which user they're interested in. One possible way to achieve this result is by using route parameters. Route parameters are named segments of the URL, delimited by slashes (/). Each segment captures the value of the part of the URL which matches its position. The captured values can be found in the <code>req.params</code> object.",
"<blockquote>route_path: '/user/:userId/book/:bookId'<br>actual_request_URL: '/user/546/book/6754' <br>req.params: {userId: '546', bookId: '6754'}</blockquote>",
"Build an echo server, mounted at the route <code>GET /:word/echo</code>. Respond with a JSON object, taking the structure <code>{echo: word}</code>. You can find the word to be repeated at <code>req.params.word</code>. You can test your route from your browser's address bar, visiting some matching routes, e.g. your-app-rootpath/freecodecamp/echo"
],
"tests": [
{
"text": "Test 1 : Your echo server should repeat words correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/eChOtEsT/echo').then(data => { assert.equal(data.echo, 'eChOtEsT', 'Test 1: the echo server is not working as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your echo server should repeat words correctly",
"testString": "getUserInput => $.get(getUserInput('url') + '/ech0-t3st/echo').then(data => { assert.equal(data.echo, 'ech0-t3st', 'Test 2: the echo server is not working as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf6",
"title": "Get Query Parameter Input from the Client",
"description": [
"Another common way to get input from the client is by encoding the data after the route path, using a query string. The query string is delimited by a question mark (?), and includes field=value couples. Each couple is separated by an ampersand (&). Express can parse the data from the query string, and populate the object <code>req.query</code>. Some characters cannot be in URLs, they have to be encoded in a <a href='https://en.wikipedia.org/wiki/Percent-encoding' target='_blank'>different format</a> before you can send them. If you use the API from JavaScript, you can use specific methods to encode/decode these characters.",
"<blockquote>route_path: '/library'<br>actual_request_URL: '/library?userId=546&bookId=6754' <br>req.query: {userId: '546', bookId: '6754'}</blockquote>",
"Build an API endpoint, mounted at <code>GET /name</code>. Respond with a JSON document, taking the structure <code>{ name: 'firstname lastname'}</code>. The first and last name parameters should be encoded in a query string e.g. <code>?first=firstname&last=lastname</code>.",
"TIP: In the following exercise we are going to receive data from a POST request, at the same <code>/name</code> route path. If you want you can use the method <code>app.route(path).get(handler).post(handler)</code>. This syntax allows you to chain different verb handlers on the same path route. You can save a bit of typing, and have cleaner code."
],
"tests": [
{
"text": "Test 1 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.get(getUserInput('url') + '/name?first=Mick&last=Jagger').then(data => { assert.equal(data.name, 'Mick Jagger', 'Test 1: \"GET /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your APi endpoint should respond with the correct name",
"testString": "getUserInput => $.get(getUserInput('url') + '/name?last=Richards&first=Keith').then(data => { assert.equal(data.name, 'Keith Richards', 'Test 2: \"GET /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf7",
"title": "Use body-parser to Parse POST Requests",
"description": [
"Besides GET there is another common http verb, it is POST. POST is the default method used to send client data with HTML forms. In the REST convention POST is used to send data to create new items in the database (a new user, or a new blog post). We dont have a database in this project, but we are going to learn how to handle POST requests anyway.",
"In these kind of requests the data doesnt appear in the URL, it is hidden in the request body. This is a part of the HTML request, also called payload. Since HTML is text based, even if you dont see the data, it doesnt mean that they are secret. The raw content of an HTTP POST request is shown below:",
"<blockquote>POST /path/subpath HTTP/1.0<br>From: john@example.com<br>User-Agent: someBrowser/1.0<br>Content-Type: application/x-www-form-urlencoded<br>Content-Length: 20<br>name=John+Doe&age=25</blockquote>",
"As you can see the body is encoded like the query string. This is the default format used by HTML forms. With Ajax we can also use JSON to be able to handle data having a more complex structure. There is also another type of encoding: multipart/form-data. This one is used to upload binary files.",
"In this exercise we will use an urlencoded body.",
"To parse the data coming from POST requests, you have to install a package: the body-parser. This package allows you to use a series of middleware, which can decode data in different formats. See the docs <a href=\"https://github.com/expressjs/body-parser\" target=\"_blank\" >here</a>.",
"Install the body-parser module in your package.json. Then require it at the top of the file. Store it in a variable named bodyParser.",
"The middleware to handle url encoded data is returned by <code>bodyParser.urlencoded({extended: false})</code>. <code>extended=false</code> is a configuration option that tells the parser to use the classic encoding. When using it, values can be only strings or arrays. The extended version allows more data flexibility, but it is outmatched by JSON. Pass to <code>app.use()</code> the function returned by the previous method call. As usual, the middleware must be mounted before all the routes which need it."
],
"tests": [
{
"text": "The 'body-parser' middleware should be mounted",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/add-body-parser').then(data => { assert.isAbove(data.mountedAt, 0, '\"body-parser\" is not mounted correctly') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb2367417b2b2512bf8",
"title": "Get Data from POST Requests",
"description": [
"Mount a POST handler at the path <code>/name</code>. Its the same path as before. We have prepared a form in the html frontpage. It will submit the same data of exercise 10 (Query string). If the body-parser is configured correctly, you should find the parameters in the object <code>req.body</code>. Have a look at the usual library example:",
"<blockquote>route: POST '/library'<br>urlencoded_body: userId=546&bookId=6754 <br>req.body: {userId: '546', bookId: '6754'}</blockquote>",
"Respond with the same JSON object as before: <code>{name: 'firstname lastname'}</code>. Test if your endpoint works using the html form we provided in the app frontpage.",
"Tip: There are several other http methods other than GET and POST. And by convention there is a correspondence between the http verb, and the operation you are going to execute on the server. The conventional mapping is:",
"POST (sometimes PUT) - Create a new resource using the information sent with the request,",
"GET - Read an existing resource without modifying it,",
"PUT or PATCH (sometimes POST) - Update a resource using the data sent,",
"DELETE => Delete a resource.",
"There are also a couple of other methods which are used to negotiate a connection with the server. Except from GET, all the other methods listed above can have a payload (i.e. the data into the request body). The body-parser middleware works with these methods as well."
],
"tests": [
{
"text": "Test 1 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.post(getUserInput('url') + '/name', {first: 'Mick', last: 'Jagger'}).then(data => { assert.equal(data.name, 'Mick Jagger', 'Test 1: \"POST /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Test 2 : Your API endpoint should respond with the correct name",
"testString": "getUserInput => $.post(getUserInput('url') + '/name', {first: 'Keith', last: 'Richards'}).then(data => { assert.equal(data.name, 'Keith Richards', 'Test 2: \"POST /name\" route does not behave as expected') }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
}
]
}

View File

@ -0,0 +1,271 @@
{
"name": "Managing Packages with npm",
"order": 1,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb3367417b2b2512bfb",
"title": "How to Use package.json, the Core of Any Node.js Project or npm Package",
"description": [
"The file package.json is the center of any Node.js project or npm package. It stores information about your project just like the &lt;head&gt;-section in a HTML document describes the content of a webpage. The package.json consists of a single JSON-object where information is stored in \"key\": value-pairs. There are only two required fields in a minimal package.json - name and version - but its a good practice to provide additional information about your project that could be useful to future users or maintainers.",
"The author-field",
"If you go to the Glitch project that you set up previously and look at on the left side of your screen, youll find the file tree where you can see an overview of the various files in your project. Under the file trees back-end section, youll find package.json - the file that well be improving in the next couple of challenges.",
"One of the most common pieces of information in this file is the author-field that specifies whos the creator of a project. It can either be a string or an object with contact details. The object is recommended for bigger projects but in our case, a simple string like the following example will do.",
"<code>\"author\": \"Jane Doe\",</code>",
"Instructions",
"Add your name to the author-field in the package.json of your Glitch project.",
"Remember that youre writing JSON.",
"All field-names must use double-quotes (\"), e.g. \"author\"",
"All fields must be separated with a comma (,)"
],
"tests": [
{
"text": "package.json should have a valid \"author\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.author, '\"author\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb3367417b2b2512bfc",
"title": "Add a Description to Your package.json",
"description": [
"The next part of a good package.json is the description-field, where a short but informative description about your project belongs.",
"If you some day plan to publishing a package to npm, remember that this is the string that should sell your idea to the user when they decide whether to install your package or not. However, thats not the only use case for the description: Since its a great way to summarize what a project does, its just as important for your normal Node.js-projects to help other developers, future maintainers or even your future self understand the project quickly.",
"Regardless of what you plan for your project, a description is definitely recommended. Lets add something similar to this:",
"<code>\"description\": \"A project that does something awesome\",</code>",
"Instructions",
"Add a description to the package.json in your Glitch project.",
"Remember to use double-quotes for field-names (\") and commas (,) to separate fields."
],
"tests": [
{
"text": "package.json should have a valid \"description\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.description, '\"description\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bfd",
"title": "Add Keywords to Your package.json",
"description": [
"The keywords-field is where you can describe your project using related keywords.",
"Example",
"<code>\"keywords\": [ \"descriptive\", \"related\", \"words\" ],</code>",
"As you can see, this field is structured as an array of double-quoted strings.",
"Instructions",
"Add an array of suitable strings to the keywords-field in the package.json of your Glitch project.",
"One of the keywords should be freecodecamp."
],
"tests": [
{
"text": "package.json should have a valid \"keywords\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.keywords, '\"keywords\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"keywords\" field should be an Array",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.isArray(packJson.keywords, '\"keywords\" is not an array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"keywords\" should include \"freecodecamp\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.include(packJson.keywords, 'freecodecamp', '\"keywords\" does not include \"freecodecamp\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bfe",
"title": "Add a License to Your package.json",
"description": [
"The license-field is where you inform users of your project what they are allowed to do with it.",
"Some common licenses for open source projects include MIT and BSD. http://choosealicense.com is a great resource if you want to learn more about what license could fit your project.",
"License information is not required. Copyright laws in most countries will give you ownership of what you create by default. However, its always a good practice to explicitly state what users can and cant do.",
"Example",
"<code>\"license\": \"MIT\",</code>",
"Instructions",
"Fill the license-field in the package.json of your Glitch project as you find suitable."
],
"tests": [
{
"text": "package.json should have a valid \"license\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.license, '\"license\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb4367417b2b2512bff",
"title": "Add a Version to Your package.json",
"description": [
"The version is together with name one of the required fields in a package.json. This field describes the current version of your project.",
"Example",
"<code>\"version\": \"1.2\",</code>",
"Instructions",
"Add a version to the package.json in your Glitch project."
],
"tests": [
{
"text": "package.json should have a valid \"version\" key",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert(packJson.version, '\"version\" is missing'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb4367417b2b2512c00",
"title": "Expand Your Project with External Packages from npm",
"description": [
"One of the biggest reasons to use a package manager is their powerful dependency management. Instead of manually having to make sure that you get all dependencies whenever you set up a project on a new computer, npm automatically installs everything for you. But how can npm know exactly what your project needs? Meet the dependencies-section of your package.json.",
"In the dependencies-section, packages your project require are stored using the following format:",
"<code>\"dependencies\": {</code>",
"<code> \"package-name\": \"version\",</code>",
"<code> \"express\": \"4.14.0\"</code>",
"<code>}</code>",
"Instructions",
"Add version 2.14.0 of the package moment to the dependencies-field of your package.json",
"Moment is a handy library for working with time and dates."
],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should be \"2.14.0\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.14\\.0/, 'Wrong version of \"moment\" installed. It should be 2.14.0'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c01",
"title": "Manage npm Dependencies By Understanding Semantic Versioning",
"description": [
"Versions of the npm packages in the dependencies-section of your package.json follow whats called Semantic Versioning (SemVer), an industry standard for software versioning aiming to make it easier to manage dependencies. Libraries, frameworks or other tools published on npm should use SemVer in order to clearly communicate what kind of changes that projects who depend on the package can expect if they update.",
"SemVer doesnt make sense in projects without public APIs - so unless your project is similar to the examples above, use another versioning format.",
"So why do you need to understand SemVer?",
"Knowing SemVer can be useful when you develop software that use external dependencies (which you almost always do). One day, your understanding of these numbers will save you from accidentally introducing breaking changes to your project without understanding why things “that worked yesterday” suddenly doesnt.",
"This is how Semantic Versioning works according to the official website:",
"Given a version number MAJOR.MINOR.PATCH, increment the:",
"MAJOR version when you make incompatible API changes,",
"MINOR version when you add functionality in a backwards-compatible manner, and",
"PATCH version when you make backwards-compatible bug fixes.",
"This means that PATCHes are bug fixes and MINORs add new features but neither of them break what worked before. Finally, MAJORs add changes that wont work with earlier versions.",
"Example",
"A semantic version number: 1.3.8",
"Instructions",
"In the dependencies-section of your package.json, change the version of moment to match MAJOR version 2, MINOR version 10 and PATCH version 2"
],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should be \"2.10.2\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^[\\^\\~]?2\\.10\\.2/, 'Wrong version of \"moment\". It should be 2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c02",
"title": "Use the Tilde-Character to Always Use the Latest Patch Version of a Dependency",
"description": [
"In the last challenge, we told npm to only include a specific version of a package. Thats a useful way to freeze your dependencies if you need to make sure that different parts of your project stay compatible with each other. But in most use cases you dont want to miss bug fixes, since they often include important security patches and (hopefully) dont break things in doing so.",
"To allow a npm dependency to get updated to the latest PATCH-version, you can prefix the dependencys version with the tilde-character (~). In package.json, our current rule for how npm may upgrade moment is to use a specific version only (2.10.2), but we want to allow the latest 2.10.x-version.",
"Example",
"<code>\"some-package-name\": \"~1.3.8\" allows updates to any 1.3.x version.</code>",
"Instructions",
"Use the tilde-character (~) to prefix the version of moment in your dependencies and allow npm to update it to any new PATCH release.",
"Note that the version numbers themselves not should be changed."
],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should match \"~2.10.2\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\~2\\.10\\.2/, 'Wrong version of \"moment\". It should be ~2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c03",
"title": "Use the Caret-Character to Use the Latest Minor Version of a Dependency",
"description": [
"Similar to how the tilde (~) we learned about in the last challenge allow npm to install the latest PATCH for a dependency, the caret (^) allows npm to install future updates as well. The difference is that the caret will allow both MINOR updates and PATCHes.",
"At the moment, your current version of moment should be ~2.10.2 which allows npm to install to the latest 2.10.x-version. If we instead were to use the caret (^) as our version prefix, npm would instead be allowed to update to any 2.x.x-version.",
"Example",
"<code>\"some-package-name\": \"^1.3.8\" allows updates to any 1.x.x version.</code>",
"Instructions",
"Use the caret-character (^) to prefix the version of moment in your dependencies and allow npm to update it to any new MINOR release.",
"Note that the version numbers themselves not should be changed."
],
"tests": [
{
"text": "\"dependencies\" should include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'moment', '\"dependencies\" does not include \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"moment\" version should match \"^2.x.x\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.match(packJson.dependencies.moment, /^\\^2\\./, 'Wrong version of \"moment\". It should be ^2.10.2'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb5367417b2b2512c04",
"title": "Remove a Package from Your Dependencies",
"description": [
"Now youve tested a few ways you can manage dependencies of your project by using the package.json's dependencies-section. Youve included external packages by adding them to the file and even told npm what types of versions you want by using special characters as the tilde (~) or the caret (^).",
"But what if you want to remove an external package that you no longer need? You might already have guessed it - Just remove the corresponding \"key\": value-pair for that from your dependencies.",
"This same method applies to removing other fields in your package.json as well",
"Instructions",
"Remove the package moment from your dependencies.",
"Make sure you have the right amount of commas after removing it."
],
"tests": [
{
"text": "\"dependencies\" should not include \"moment\"",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.notProperty(packJson.dependencies, 'moment', '\"dependencies\" still includes \"moment\"'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
}
]
}

View File

@ -0,0 +1,268 @@
{
"name": "MongoDB and Mongoose",
"order": 3,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d7fb6367417b2b2512c06",
"title": "Install and Set Up Mongoose",
"description": [
"Add mongodb and mongoose to the projects package.json. Then require mongoose. Store your mLab database URI in the private .env file as MONGO_URI. Connect to the database using mongoose.connect(<Your URI>)"
],
"tests": [
{
"text": "\"mongodb\" dependency should be in package.json",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/file/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongodb'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"mongoose\" dependency should be in package.json",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/file/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongoose'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "\"mongoose\" should be connected to a database",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/is-mongoose-ok').then(data => {assert.isTrue(data.isMongooseOk, 'mongoose is not connected')}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb6367417b2b2512c07",
"title": "Create a Model",
"description": [
"First of all we need a Schema. Each schema maps to a MongoDB collection. It defines the shape of the documents within that collection.",
"Schemas are building block for Models. They can be nested to create complex models, but in this case well keep things simple.",
"A model allows you to create instances of your objects, called documents.",
"Create a person having this prototype :",
"<code>- Person Prototype -</code>",
"<code>--------------------</code>",
"<code>name : string [required]</code>",
"<code>age : number</code>",
"<code>favoriteFoods : array of strings (*) </code>",
"Use the mongoose basic schema types. If you want you can also add",
"more fields, use simple validators like required or unique,",
"and set default values. See the <a href='http://mongoosejs.com/docs/guide.html'>mongoose docs</a>.",
"[C]RUD Part I - CREATE",
"Note: Glitch is a real server, and in real servers the interactions with the db happen in handler functions. These function are executed when some event happens (e.g. someone hits an endpoint on your API). Well follow the same approach in these exercises. The done() function is a callback that tells us that we can proceed after completing an asynchronous operation such as inserting, searching, updating or deleting. Its following the Node convention and should be called as done(null, data) on success, or done(err) on error.",
"Warning - When interacting with remote services, errors may occur !",
"<code>/* Example */</code>",
"<code>var someFunc = function(done) {</code>",
"<code> //... do something (risky) ...</code>",
"<code> if(error) return done(error);</code>",
"<code> done(null, result);</code>",
"<code>};</code>"
],
"tests": [
{
"text": "Creating an instance from a mongoose schema should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/mongoose-model', {name: 'Mike', age: 28, favoriteFoods: ['pizza', 'cheese']}).then(data => { assert.equal(data.name, 'Mike', '\"model.name\" is not what expected'); assert.equal(data.age, '28', '\"model.age\" is not what expected'); assert.isArray(data.favoriteFoods, '\"model.favoriteFoods\" is not an Array'); assert.include(data.favoriteFoods, 'pizza', '\"model.favoriteFoods\" does not include the expected items'); assert.include(data.favoriteFoods, 'cheese', '\"model.favoriteFoods\" does not include the expected items'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb6367417b2b2512c09",
"title": "Create and Save a Record of a Model",
"description": [
"Create a document instance using the Person constructor you build before. Pass to the constructor an object having the fields name, age, and favoriteFoods. Their types must be conformant to the ones in the Person Schema. Then call the method document.save() on the returned document instance. Pass to it a callback using the Node convention. This is a common pattern, all the following CRUD methods take a callback function like this as the last argument.",
"<code>/* Example */</code>",
"<code>// ...</code>",
"<code>person.save(function(err, data) {</code>",
"<code>// ...do your stuff here...</code>",
"<code>});</code>"
],
"tests": [
{
"text": "Creating and saving a db item should succeed",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/create-and-save-person').then(data => { assert.isString(data.name, '\"item.name\" should be a String'); assert.isNumber(data.age, '28', '\"item.age\" should be a Number'); assert.isArray(data.favoriteFoods, '\"item.favoriteFoods\" should be an Array'); assert.equal(data.__v, 0, 'The db item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0a",
"title": "Create Many Records with model.create()",
"description": [
"Sometimes you need to create many instances of your models, e.g. when seeding a database with initial data. Model.create() takes an array of objects like [{name: 'John', ...}, {...}, ...] as the first argument, and saves them all in the db. Create many people with Model.create(), using the function argument arrayOfPeople."
],
"tests": [
{
"text": "Creating many db items at once should succeed",
"testString":
"getUserInput => $.ajax({url: getUserInput('url') + '/_api/create-many-people', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'John', age: 24, favoriteFoods: ['pizza', 'salad']}, {name: 'Mary', age: 21, favoriteFoods: ['onions', 'chicken']}])}).then(data => { assert.isArray(data, 'the response should be an array'); assert.equal(data.length, 2, 'the response does not contain the expected number of items'); assert.equal(data[0].name, 'John', 'The first item is not correct'); assert.equal(data[0].__v, 0, 'The first item should be not previously edited'); assert.equal(data[1].name, 'Mary', 'The second item is not correct'); assert.equal(data[1].__v, 0, 'The second item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0b",
"title": "Use model.find() to Search Your Database",
"description": [
"Find all the people having a given name, using Model.find() -> [Person]",
"In its simplest usage, Model.find() accepts a query document (a JSON object ) as the first argument, then a callback. It returns an array of matches. It supports an extremely wide range of search options. Check it in the docs. Use the function argument personName as search key."
],
"tests": [
{
"text": "Find all items corresponding to a criteria should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/find-all-by-name', {name: 'r@nd0mN4m3', age: 24, favoriteFoods: ['pizza']}).then(data => { assert.isArray(data, 'the response should be an Array'); assert.equal(data[0].name, 'r@nd0mN4m3', 'item.name is not what expected'); assert.equal(data[0].__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0c",
"title":
"Use model.findOne() to Return a Single Matching Document from Your Database",
"description": [
"Model.findOne() behaves like .find(), but it returns only one document (not an array), even if there are multiple items. It is especially useful when searching by properties that you have declared as unique. Find just one person which has a certain food in her favorites, using Model.findOne() -> Person. Use the function argument food as search key."
],
"tests": [
{
"text": "Find one item should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/find-one-by-food', {name: 'Gary', age: 46, favoriteFoods: ['chicken salad']}).then(data => { assert.equal(data.name, 'Gary', 'item.name is not what expected'); assert.deepEqual(data.favoriteFoods, ['chicken salad'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb7367417b2b2512c0d",
"title": "Use model.findById() to Search Your Database By _id",
"description": [
"When saving a document, mongodb automatically adds the field _id, and set it to a unique alphanumeric key. Searching by _id is an extremely frequent operation, so moongose provides a dedicated method for it. Find the (only!!) person having a given _id, using Model.findById() -> Person. Use the function argument personId as search key."
],
"tests": [
{
"text": "Find an item by Id should succeed",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/find-by-id').then(data => { assert.equal(data.name, 'test', 'item.name is not what expected'); assert.equal(data.age, 0, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['none'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'The item should be not previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c0e",
"title": "Perform Classic Updates by Running Find, Edit, then Save",
"description": [
"In the good old days this was what you needed to do if you wanted to edit a document and be able to use it somehow e.g. sending it back in a server response. Mongoose has a dedicated updating method : Model.update(). It is binded to the low-level mongo driver. It can bulk edit many documents matching certain criteria, but it doesnt send back the updated document, only a status message. Furthermore it makes model validations difficult, because it just directly calls the mongo driver.",
"Find a person by _id ( use any of the above methods ) with the parameter personId as search key. Add “hamburger” to the list of her favoriteFoods (you can use Array.push()). Then - inside the find callback - save() the updated Person.",
"[*] Hint: This may be tricky if in your Schema you declared favoriteFoods as an Array, without specifying the type (i.e. [String]). In that casefavoriteFoods defaults to Mixed type, and you have to manually mark it as edited using document.markModified('edited-field'). (http://mongoosejs.com/docs/schematypes.html - #Mixed )"
],
"tests": [
{
"text": "Find-edit-update an item should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/find-edit-save', {name:'Poldo', age: 40, favoriteFoods:['spaghetti']}).then(data => { assert.equal(data.name, 'Poldo', 'item.name is not what expected'); assert.equal(data.age, 40, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['spaghetti', 'hamburger'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 1, 'The item should be previously edited'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c0f",
"title":
"Perform New Updates on a Document Using model.findOneAndUpdate()",
"description": [
"Recent versions of mongoose have methods to simplify documents updating. Some more advanced features (i.e. pre/post hooks, validation) behave differently with this approach, so the Classic method is still useful in many situations. findByIdAndUpdate() can be used when searching by Id.",
"Find a person by Name and set her age to 20. Use the function parameter personName as search key.",
"Hint: We want you to return the updated document. To do that you need to pass the options document { new: true } as the 3rd argument to findOneAndUpdate(). By default these methods return the unmodified object."
],
"tests": [
{
"text": "findOneAndUpdate an item should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/find-one-update', {name:'Dorian Gray', age: 35, favoriteFoods:['unknown']}).then(data => { assert.equal(data.name, 'Dorian Gray', 'item.name is not what expected'); assert.equal(data.age, 20, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['unknown'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0, 'findOneAndUpdate does not increment version by design !!!'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c10",
"title": "Delete One Document Using model.findByIdAndRemove",
"description": [
"Delete one person by her _id. You should use one of the methods findByIdAndRemove() or findOneAndRemove(). They are like the previous update methods. They pass the removed document to the cb. As usual, use the function argument personId as search key."
],
"tests": [
{
"text": "Deleting an item should succeed",
"testString":
"getUserInput => $.post(getUserInput('url') + '/_api/remove-one-person', {name:'Jason Bourne', age: 36, favoriteFoods:['apples']}).then(data => { assert.equal(data.name, 'Jason Bourne', 'item.name is not what expected'); assert.equal(data.age, 36, 'item.age is not what expected'); assert.deepEqual(data.favoriteFoods, ['apples'], 'item.favoriteFoods is not what expected'); assert.equal(data.__v, 0); assert.equal(data.count, 0, 'the db items count is not what expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb8367417b2b2512c11",
"title": "Delete Many Documents with model.remove()",
"description": [
"Model.remove() is useful to delete all the documents matching given criteria. Delete all the people whose name is “Mary”, using Model.remove(). Pass it to a query document with the “name” field set, and of course a callback.",
"Note: Model.remove() doesnt return the deleted document, but a JSON object containing the outcome of the operation, and the number of items affected. Dont forget to pass it to the done() callback, since we use it in tests."
],
"tests": [
{
"text": "Deleting many items at once should succeed",
"testString":
"getUserInput => $.ajax({url: getUserInput('url') + '/_api/remove-many-people', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'Mary', age: 16, favoriteFoods: ['lollipop']}, {name: 'Mary', age: 21, favoriteFoods: ['steak']}])}).then(data => { assert.isTrue(!!data.ok, 'The mongo stats are not what expected'); assert.equal(data.n, 2, 'The number of items affected is not what expected'); assert.equal(data.count, 0, 'the db items count is not what expected'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "587d7fb9367417b2b2512c12",
"title": "Chain Search Query Helpers to Narrow Search Results",
"description": [
"If you dont pass the callback as the last argument to Model.find() (or to the other search methods), the query is not executed. You can store the query in a variable for later use. This kind of object enables you to build up a query using chaining syntax. The actual db search is executed when you finally chain the method .exec(). Pass your callback to this last method. There are many query helpers, here well use the most famous ones.",
"Find people who like \"burrito\". Sort them by name, limit the results to two documents, and hide their age. Chain .find(), .sort(), .limit(), .select(), and then .exec(). Pass the done(err, data) callback to exec()."
],
"tests": [
{
"text": "Chaining query helpers should succeed",
"testString":
"getUserInput => $.ajax({url: getUserInput('url') + '/_api/query-tools', type: 'POST', contentType:'application/json', data: JSON.stringify([{name: 'Pablo', age: 26, favoriteFoods: ['burrito', 'hot-dog']}, {name: 'Bob', age: 23, favoriteFoods: ['pizza', 'nachos']}, {name: 'Ashley', age: 32, favoriteFoods: ['steak', 'burrito']}, {name: 'Mario', age: 51, favoriteFoods: ['burrito', 'prosciutto']} ]) }).then(data => { assert.isArray(data, 'the response should be an Array'); assert.equal(data.length, 2, 'the data array length is not what expected'); assert.notProperty(data[0], 'age', 'The returned first item has too many properties'); assert.equal(data[0].name, 'Ashley', 'The returned first item name is not what expected'); assert.notProperty(data[1], 'age', 'The returned second item has too many properties'); assert.equal(data[1].name, 'Mario', 'The returned second item name is not what expected');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
}
]
}

View File

@ -0,0 +1,692 @@
{
"name": "Advanced Node and Express",
"order": 3,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "5895f700f9fc0f352b528e63",
"title": "Set up a Template Engine",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"A template engine enables you to use static template files (such as those written in <em>Pug</em>) in your app. At runtime, the template engine replaces variables in a template file with actual values which can be supplied by your server, and transforms the template into a static HTML file that is then sent to the client. This approach makes it easier to design an HTML page and allows for displaying of variables on the page without needing to make an API call from the client.",
"To set up <em>Pug</em> for use in your project, you will need to add it as a dependency first in your package.json. <code>\"pug\": \"^0.1.0\"</code>",
"Now to tell Node/Express to use the templating engine you will have to tell your express <b>app</b> to <b>set</b> 'pug' as the 'view-engine'. <code>app.set('view engine', 'pug')</code>",
"Lastly, you should change your response to the request for the index route to <code>res.render</code> with the path to the view <em>views/pug/index.pug</em>.",
"If all went as planned, you should refresh your apps home page and see a small message saying you're successfully rending the Pug from our Pug file! Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Pug is a dependency",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'pug', 'Your project should list \"pug\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "View engine is Pug",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")view engine('|\"),( |)('|\")pug('|\")/gi, 'Your project should set Pug as a view engine'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Pug is working",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-success-message/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70bf9fc0f352b528e64",
"title": "Use a Template Engine's Powers",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"One of the greatest features of using a template engine is being able to pass variables from the server to the template file before rendering it to HTML.",
"In your Pug file, you're about to use a variable by referencing the variable name as <code>#{variable_name}</code> inline with other text on an element or by using an equal side on the element without a space such as <code>p= variable_name</code> which sets that p elements text to equal the variable.",
"We strongly recommend looking at the syntax and structure of Pug <a href='https://github.com/pugjs/pug'>here</a> on their Githubs README. Pug is all about using whitespace and tabs to show nested elements and cutting down on the amount of code needed to make a beautiful site.",
"Looking at our pug file 'index.pug' included in your project, we used the variables <em>title</em> and <em>message</em>",
"To pass those alone from our server, you will need to add an object as a second argument to your <em>res.render</em> with the variables and their value. For example, pass this object along setting the variables for your index view: <code>{title: 'Hello', message: 'Please login'</code>",
"It should look like: <code>res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});</code>",
"Now refresh your page and you should see those values rendered in your view in the correct spot as laid out in your index.pug file! Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Pug render variables correct",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/') .then(data => { assert.match(data, /pug-variable(\"|')>Please login/gi, 'Your projects home page should now be rendered by pug with the projects .pug file unaltered'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e65",
"title": "Set up Passport",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"It's time to set up <em>Passport</em> so we can finally start allowing a user to register or login to an account! In addition to Passport, we will use Express-session to handle sessions. Using this middleware saves the session id as a cookie in the client and allows us to access the session data using that id on the server. This way we keep personal account information out of the cookie used by the client to verify to our server they are authenticated and just keep the <em>key</em> to access the data stored on the server.",
"To set up Passport for use in your project, you will need to add it as a dependency first in your package.json. <code>\"passport\": \"^0.3.2\"</code>",
"In addition, add Express-session as a dependency now as well. Express-session has a ton of advanced features you can use but for now we're just going to use the basics! <code>\"express-session\": \"^1.15.0\"</code>",
"You will need to set up the session settings now and initialize Passport. Be sure to first create the variables 'session' and 'passport' to require 'express-session' and 'passport' respectively.",
"To set up your express app to use use the session we'll define just a few basic options. Be sure to add 'SESSION_SECRET' to your .env file and give it a random value. This is used to compute the hash used to encrypt your cookie!",
"<pre>app.use(session({\n secret: process.env.SESSION_SECRET,\n resave: true,\n saveUninitialized: true,\n}));</pre>",
"As well you can go ahead and tell your express app to <b>use</b> 'passport.initialize()' and 'passport.session()'. (For example, <code>app.use(passport.initialize());</code>)",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/338a9c5a326923c3826a666d430e65c3'>here</a>."
],
"tests": [
{
"text": "Passort and Express-session are dependencies",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport', 'Your project should list \"passport\" as a dependency'); assert.property(packJson.dependencies, 'express-session', 'Your project should list \"express-session\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Dependencies correctly required",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport(\"|')/gi, 'You should have required passport'); assert.match(data, /require.*(\"|')express-session(\"|')/gi, 'You should have required express-session'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Express app uses new dependencies",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.initialize/gi, 'Your express app should use \"passport.initialize()\"'); assert.match(data, /passport.session/gi, 'Your express app should use \"passport.session()\"'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Session and session secret correctly set up",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /secret:( |)process.env.SESSION_SECRET/gi, 'Your express app should have express-session set up with your secret as process.env.SESSION_SECRET'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e66",
"title": "Serialization of a User Object",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Serialization and deserialization are important concepts in regards to authentication. To serialize an object means to convert its contents into a small <em>key</em> essentially that can then be deserialized into the original object. This is what allows us to know whos communicated with the server without having to send the authentication data like username and password at each request for a new page.",
"To set this up properly, we need to have a serialize function and a deserialize function. In passport we create these with <code>passport.serializeUser( OURFUNCTION )</code> and <code>passport.deserializeUser( OURFUNCTION )</code>",
"The serializeUser is called with 2 arguments, the full user object and a callback used by passport. Returned in the callback should be a unique key to identify that user- the easiest one to use being the users _id in the object as it should be unique as it generated by MongoDb. Similarly deserializeUser is called with that key and a callback function for passport as well, but this time we have to take that key and return the users full object to the callback. To make a query search for a Mongo _id you will have to create <code>const ObjectID = require('mongodb').ObjectID;</code>, and then to use it you call <code>new ObjectID(THE_ID)</code>. Be sure to add MongoDB as a dependency. You can see this in the examples below:",
"<pre>passport.serializeUser((user, done) => {\n done(null, user._id);\n });</pre><br><pre>passport.deserializeUser((id, done) => {\n db.collection('users').findOne(\n {_id: new ObjectID(id)},\n (err, doc) => {\n done(null, doc);\n }\n );\n });</pre>",
"NOTE: This deserializeUser will throw an error until we set up the DB in the next step so comment out the whole block and just call <code>done(null, null)</code> in the function deserializeUser.",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Serialize user function correct",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.serializeUser/gi, 'You should have created your passport.serializeUser function'); assert.match(data, /null, user._id/gi, 'There should be a callback in your serializeUser with (null, user._id)'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Deserialize user function correct",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.deserializeUser/gi, 'You should have created your passport.deserializeUser function'); assert.match(data, /null,( |)null/gi, 'There should be a callback in your deserializeUser with (null, null) for now'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "MongoDB is a dependency",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'mongodb', 'Your project should list \"mongodb\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Mongodb properly required including the ObjectId",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')mongodb(\"|')/gi, 'You should have required mongodb'); assert.match(data, /new ObjectID.*id/gi, 'Even though the block is commented out, you should use new ObjectID(id) for when we add the database'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70cf9fc0f352b528e67",
"title": "Implement the Serialization of a Passport User",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Right now we're not loading an actually users object since we haven't set up our database. This can be done many different ways, but for our project we will connect to the database once when we start the server and keep a persistent connection for the full life-cycle of the app.",
"To do this, add MongoDB as a dependency and require it in your server. (<code>const mongo = require('mongodb').MongoClient;</code>)",
"Now we want to the connect to our database then start listening for requests. The purpose of this is to not allow requests before our database is connected or if there is a database error. To accomplish you will want to encompass your serialization and your app listener in the following:",
"<pre>mongo.connect(process.env.DATABASE, (err, db) => {\n if(err) {\n console.log('Database error: ' + err);\n } else {\n console.log('Successful database connection');\n\n //serialization and app.listen\n\n}});</pre>",
"You can now uncomment the block in deserializeUser and remove your <code>done(null, null)</code>. Be sure to set <em>DATABASE</em> in your .env file to your database's connection string (for example: <code>DATABASE=mongodb://admin:pass@mlab.com:12345/my-project</code>). You can set up a free database on <a href='https://mlab.com/welcome/'>mLab</a>. Congratulations- you've finished setting up serialization!",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/e192e809a1d27cb80dc2c6d3467b7477'>here</a>."
],
"tests": [
{
"text": "Database connection is present",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /mongo.connect/gi, 'You should have created a connection to your database'); assert.match(data, /mongo.connect[^]*app.listen[^]*}[^]*}/gi, 'You should have your app.listen nested at within your database connection at the bottom'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text":
"Deserialization is now correctly using the DB and <code>done(null, null)</code> is erased",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.notMatch(data, /null,( |)null/gi, 'The callback in deserializeUser of (null, null) should be completely removed for the db block uncommented out'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e68",
"title": "Authentication Strategies",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"A strategy is a way of authenticating a user. You can use a strategy for allowing users to authenticate based on locally saved information (if you have them register first) or from a variety of providers such as Google or Github. For this project we will set up a local strategy. To see a list of the 100's of strategies, visit Passports site <a href='http://passportjs.org/'>here</a>.",
"Add <em>passport-local</em> as a dependency and add it to your server as follows: <code>const LocalStrategy = require('passport-local');</code>",
"Now you will have to tell passport to <b>use</b> an instantiated LocalStartegy object with a few settings defined. Make sure this as well as everything from this point on is encapsulated in the database connection since it relies on it! <pre>passport.use(new LocalStrategy(\n function(username, password, done) {\n db.collection('users').findOne({ username: username }, function (err, user) {\n console.log('User '+ username +' attempted to log in.');\n if (err) { return done(err); }\n if (!user) { return done(null, false); }\n if (password !== user.password) { return done(null, false); }\n return done(null, user);\n });\n }\n));</pre> This is defining the process to take when we try to authenticate someone locally. First it tries to find a user in our database with the username entered, then it checks for the password to match, then finally if no errors have popped up that we checked for, like an incorrect password, the users object is returned and they are authenticated.",
"Many strategies are set up using different settings, general it is easy to set it up based on the README in that strategies repository though. A good example of this is the Github strategy where we don't need to worry about a username or password because the user will be sent to Github's auth page to authenticate and as long as they are logged in and agree then Github returns their profile for us to use.",
"In the next step we will set up how to actually call the authentication strategy to validate a user based on form data! Submit your page when you think you've got it right up to this point."
],
"tests": [
{
"text": "Passport-local is a dependency",
"testString":
" getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-local', 'Your project should list \"passport-local \" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Passport-local correctly required and setup",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport-local(\"|')/gi, 'You should have required passport-local'); assert.match(data, /new LocalStrategy/gi, 'You should have told passport to use a new strategy'); assert.match(data, /findOne/gi, 'Your new local strategy should use the findOne query to find a username based on the inputs'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e69",
"title": "How to Use Passport Strategies",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"In the index.pug file supplied there is actually a login form. It has previously been hidden because of the inline javascript <code>if showLogin</code> with the form indented after it. Before showLogin as a variable was never defined, it never rendered the code block containing the form. Go ahead and on the res.render for that page add a new variable to the object <code>showLogin: true</code>. When you refresh your page, you should then see the form! This form is set up to <b>POST</b> on <em>/login</em> so this is where we should set up to accept the POST and authenticate the user.",
"For this challenge you should add the route /login to accept a POST request. To authenticate on this route you need to add a middleware to do so before then sending a response. This is done by just passing another argument with the middleware before your <code>function(req,res)</code> with your response! The middleware to use is <code>passport.authenticate('local')</code>.",
"<em>passport.authenticate</em> can also take some options as an argument such as: <code>{ failureRedirect: '/' }</code> which is incredibly useful so be sure to add that in as well. As a response after using the middleware (which will only be called if the authentication middleware passes) should be to redirect the user to <em>/profile</em> and that route should render the view 'profile.pug'.",
"If the authentication was successful, the user object will be saved in <em>req.user</em>.",
"Now at this point if you enter a username and password in the form, it should redirect to the home page <em>/</em> and in the console of your server should be 'User {USERNAME} attempted to log in.' since we currently cannot login a user who isn't registered.",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/8a335d1a68ed9170da02bb9d8f5b71d5'>here</a>."
],
"tests": [
{
"text": "All steps correctly implemented in the server.js",
"testString":
" getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /showLogin:( |)true/gi, 'You should be passing the variable \"showLogin\" as true to your render function for the homepage'); assert.match(data, /failureRedirect:( |)('|\")\\/('|\")/gi, 'Your code should include a failureRedirect to the \"/\" route'); assert.match(data, /login[^]*post[^]*local/gi, 'You should have a route for login which accepts a POST and passport.authenticates local'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "A POST request to /login correctly redirects to /",
"testString":
"getUserInput => $.post(getUserInput('url')+ '/login') .then(data => { assert.match(data, /Looks like this page is being rendered from Pug into HTML!/gi, 'A login attempt at this point should redirect to the homepage since we do not have any registered users'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70df9fc0f352b528e6a",
"title": "Create New Middleware",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"As in, any user can just go to /profile whether they authenticated or not by typing in the url. We want to prevent this by checking if the user is authenticated first before rendering the profile page. This is the perfect example of when to create a middleware.",
"The challenge here is creating the middleware function <code>ensureAuthenticated(req, res, next)</code>, which will check if a user is authenticated by calling passports isAuthenticated on the <em>request</em> which in turn checks for <em>req.user</em> is to be defined. If it is then <em>next()</em> should be called, otherwise we can just respond to the request with a redirect to our homepage to login. An implementation of this middleware is:",
"<pre>function ensureAuthenticated(req, res, next) {\n if (req.isAuthenticated()) {\n return next();\n }\n res.redirect('/');\n};</pre>",
"Now add <em>ensureAuthenticated</em> as a middleware to the request for the profile page before the argument to the get request containing the function that renders the page.",
"<pre>app.route('/profile')\n .get(ensureAuthenticated, (req,res) => {\n res.render(process.cwd() + '/views/pug/profile');\n });</pre>",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text":
"Middleware ensureAuthenticated should be implemented and on our /profile route",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /ensureAuthenticated[^]*req.isAuthenticated/gi, 'Your ensureAuthenticated middleware should be defined and utilize the req.isAuthenticated function'); assert.match(data, /profile[^]*get[^]*ensureAuthenticated/gi, 'Your ensureAuthenticated middleware should be attached to the /profile route'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text":
"A Get request to /profile correctly redirects to / since we are not authenticated",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/profile') .then(data => { assert.match(data, /Home page/gi, 'An attempt to go to the profile at this point should redirect to the homepage since we are not logged in'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "5895f70ef9fc0f352b528e6b",
"title": "How to Put a Profile Together",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Now that we can ensure the user accessing the <em>/profile</em> is authenticated, we can use the information contained in 'req.user' on our page!",
"Go ahead and pass the object containing the variable <em>username</em> equaling 'req.user.username' into the render method of the profile view. Then go to your 'profile.pug' view and add the line <code>h2.center#welcome Welcome, #{username}!</code> creating the h2 element with the class 'center' and id 'welcome' containing the text 'Welcome, ' and the username!",
"Also in the profile, add a link to <em>/logout</em>. That route will host the logic to unauthenticate a user. <code>a(href='/logout') Logout</code>",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Correctly added a Pug render variable to /profile",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /\\/views\\/pug\\/profile[^]*username:( |)req.user.username/gi, 'You should be passing the variable username with req.user.username into the render function of the profile page'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "58965611f9fc0f352b528e6c",
"title": "Logging a User Out",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Creating the logout logic is easy. The route should just unauthenticate the user and redirect to the home page instead of rendering any view.",
"In passport, unauthenticating a user is as easy as just calling <code>req.logout();</code> before redirecting.",
"<pre>app.route('/logout')\n .get((req, res) => {\n req.logout();\n res.redirect('/');\n });</pre>",
"You may have noticed we also we're not handling missing pages (404), the common way to handle this in Node is with the following middleware. Go ahead and add this in after all your other routes:",
"<pre>app.use((req, res, next) => {\n res.status(404)\n .type('text')\n .send('Not Found');\n});</pre>",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Logout route",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /req.logout/gi, 'You should be call req.logout() in youre /logout route'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Logout should redirect to the home page /",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/logout') .then(data => { assert.match(data, /Home page/gi, 'When a user logs out they should be redirected to the homepage'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "58966a17f9fc0f352b528e6d",
"title": "Registration of New Users",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Now we need to allow a new user on our site to register an account. On the res.render for the home page add a new variable to the object passed along- <code>showRegistration: true</code>. When you refresh your page, you should then see the registration form that was already created in your index.pug file! This form is set up to <b>POST</b> on <em>/register</em> so this is where we should set up to accept the POST and create the user object in the database.",
"The logic of the registration route should be as follows: Register the new user > Authenticate the new user > Redirect to /profile",
"The logic of step 1, registering the new user, should be as follows: Query database with a findOne command > if user is returned then it exists and redirect back to home <em>OR</em> if user is undefined and no error occurs then 'insertOne' into the database with the username and password and as long as no errors occur then call <em>next</em> to go to step 2, authenticating the new user, which we've already written the logic for in our POST /login route.",
"<pre>app.route('/register')\n .post((req, res, next) => {\n db.collection('users').findOne({ username: req.body.username }, function (err, user) {\n if(err) {\n next(err);\n } else if (user) {\n res.redirect('/');\n } else {\n db.collection('users').insertOne(\n {username: req.body.username,\n password: req.body.password},\n (err, doc) => {\n if(err) {\n res.redirect('/');\n } else {\n next(null, user);\n }\n }\n )\n }\n })},\n passport.authenticate('local', { failureRedirect: '/' }),\n (req, res, next) => {\n res.redirect('/profile');\n }\n);</pre>",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point <a href='https://gist.github.com/JosephLivengood/6c47bee7df34df9f11820803608071ed'>here</a>."
],
"tests": [
{
"text": "Register route and display on home",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /showRegistration:( |)true/gi, 'You should be passing the variable \"showRegistration\" as true to your render function for the homepage'); assert.match(data, /register[^]*post[^]*findOne[^]*username:( |)req.body.username/gi, 'You should have a route accepted a post request on register that querys the db with findone and the query being \"username: req.body.username\"'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Registering should work",
"testString":
"getUserInput => $.ajax({url: getUserInput('url')+ '/register',data: {username: 'freeCodeCampTester', password: 'freeCodeCampTester'},crossDomain: true, type: 'POST', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, 'I should be able to register and it direct me to my profile. CLEAR YOUR DATABASE if this test fails (each time until its right!)'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Login should work",
"testString":
"getUserInput => $.ajax({url: getUserInput('url')+ '/login',data: {username: 'freeCodeCampTester', password: 'freeCodeCampTester'}, type: 'POST', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Profile/gi, 'Login should work if previous test was done successfully and redirect successfully to the profile. Check your work and clear your DB'); assert.match(data, /freeCodeCampTester/gi, 'The profile should properly display the welcome to the user logged in'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Logout should work",
"testString":
"getUserInput => $.ajax({url: getUserInput('url')+ '/logout', type: 'GET', xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, 'Logout should redirect to home'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Profile should no longer work after logout",
"testString":
"getUserInput => $.ajax({url: getUserInput('url')+ '/profile', type: 'GET', crossDomain: true, xhrFields: { withCredentials: true }}) .then(data => { assert.match(data, /Home/gi, 'Profile should redirect to home when we are logged out now again'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "58a25c98f9fc0f352b528e7f",
"title": "Hashing Your Passwords",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Going back to the information security section you may remember that storing plaintext passwords is <em>never</em> okay. Now it is time to implement BCrypt to solve this issue.",
"<hr>Add BCrypt as a dependency and require it in your server. You will need to handle hashing in 2 key areas: where you handle registering/saving a new account and when you check to see that a password is correct on login.",
"Currently on our registeration route, you insert a user's password into the database like the following: <code>password: req.body.password</code>. An easy way to implement saving a hash instead is to add the following before your database logic <code>var hash = bcrypt.hashSync(req.body.password, 12);</code> and replacing the <code>req.body.password</code> in the database saving with just <code>password: hash</code>.",
"Finally on our authentication strategy we check for the following in our code before completing the process: <code>if (password !== user.password) { return done(null, false); }</code>. After making the previous changes, now <code>user.password</code> is a hash. Before making a change to the existing code, notice how the statement is checking if the password is NOT equal then return non-authenticated. With this in mind your code could look as follows to properly check the password entered against the hash: <code>if (!bcrypt.compareSync(password, user.password)) { return done(null, false); }</code>",
"That is all it takes to implement one of the most important security features when you have to store passwords! Submit your page when you think you've got it right."
],
"tests": [
{
"text": "BCrypt is a dependency",
"testString":
" getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'bcrypt', 'Your project should list \"bcrypt\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "BCrypt correctly required and implemented",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')bcrypt(\"|')/gi, 'You should have required bcrypt'); assert.match(data, /bcrypt.hashSync/gi, 'You should use hash the password in the registration'); assert.match(data, /bcrypt.compareSync/gi, 'You should compare the password to the hash in your strategy'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589690e6f9fc0f352b528e6e",
"title": "Clean Up Your Project with Modules",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-advancednode/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-advancednode/'>GitHub</a>.",
"Right now everything you have is in your server.js file. This can lead to hard to manage code that isn't very expandable.",
"Create 2 new files: Routes.js and Auth.js",
"Both should start with the following code: <pre>module.exports = function (app, db) {\n\n\n}</pre>",
"Now in the top of your server file, require these files like such: <code>const routes = require('./routes.js');</code>",
"Right after you establish a successful connect with the database instantiate each of them like such: <code>routes(app, db)</code>",
"Finally, take all of the routes in your server and paste them into your new files and remove them from your server file. Also take the ensureAuthenticated since we created that middleware function for routing specifically. You will have to now correctly add the dependencies in that are used, such as <code>const passport = require('passport');</code>, at the very top above the export line in your routes.js file.",
"Keep adding them until no more errors exist, and your server file no longer has any routing!",
"Now do the same thing in your auth.js file with all of the things related to authentication such as the serialization and the setting up of the local strategy and erase them from your server file. Be sure to add the dependencies in and call <code>auth(app,db)</code> in the server in the same spot. Be sure to have <code>auth(app, db)</code> before <code>routes(app, db)</code> since our registration route depends on passport being initiated!",
"Congratulations- you're at the end of this section of Advanced Node and Express and have some beautiful code to show for it! Submit your page when you think you've got it right. If you're running into errors, you can check out an example of the completed project <a href='https://glitch.com/#!/project/delicious-herring'>here</a>."
],
"tests": [
{
"text": "Modules present",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|').\\/routes.js(\"|')/gi, 'You should have required your new files'); assert.match(data, /mongo.connect[^]*routes/gi, 'Your new modules should be called after your connection to the database'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589a69f5f9fc0f352b528e70",
"title": "Implementation of Social Authentication",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The basic path this kind of authentication will follow in your app is: <ol><li>User clicks a button or link sending them to our route to authenticate using a specific strategy (EG. Github)</li><li>Your route calls <code>passport.authenticate('github')</code> which redirects them to Github.</li><li>The page the user lands on, on Github, allows them to login if they aren't already. It then asks them to approve access to their profile from our app.</li><li>The user is then returned to our app at a specific callback url with their profile if they are approved.</li><li>They are now authenticated and your app should check if it is a returning profile, or save it in your database if it is not.</li></ol>",
"Strategies with OAuth require you to have at least a <em>Client ID</em> and a <em>Client Secret</em> which is a way for them to verify who the authentication request is coming from and if it is valid. These are obtained from the site you are trying to implement authentication with, such as Github, and are unique to your app- <b>THEY ARE NOT TO BE SHARED</b> and should never be uploaded to a public repository or written directly in your code. A common practice is to put them in your <em>.env</em> file and reference them like: <code>process.env.GITHUB_CLIENT_ID</code>. For this challenge we're going to use the Github strategy.",
"Obtaining your <em>Client ID and Secret<em> from Github is done in your account profile settings under 'developer settings', then '<a href='https://github.com/settings/developers'>OAuth applications</a>'. Click 'Register a new application', name your app, paste in the url to your glitch homepage (<b>Not the project code's url</b>), and lastly for the callback url, paste in the same url as the homepage but with '/auth/github/callback' added on. This is where users will be redirected to for us to handle after authenticating on Github. Save the returned information as 'GITHUB_CLIENT_ID' and 'GITHUB_CLIENT_SECRET' in your .env file.",
"On your remixed project, create 2 routes accepting GET requests: /auth/github and /auth/github/callback. The first should only call passport to authenticate 'github' and the second should call passport to authenticate 'github' with a failure redirect to '/' and then if that is successful redirect to '/profile' (similar to our last project).",
"An example of how '/auth/github/callback' should look is similar to how we handled a normal login in our last project: <pre>app.route('/login')\n .post(passport.authenticate('local', { failureRedirect: '/' }), (req,res) => { \n res.redirect('/profile'); \n });</pre>",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/28ea2cae7e1dc6a53d7f0c42d987313b'>here</a>."
],
"tests": [
{
"text": "Route /auth/github correct",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")\\/auth\\/github('|\")[^]*get.*passport.authenticate.*github/gi, 'Route auth/github should only call passport.authenticate with github'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Route /auth/github/callback correct",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /('|\")\\/auth\\/github\\/callback('|\")[^]*get.*passport.authenticate.*github.*failureRedirect:( |)(\"|')\\/(\"|')/gi, 'Route auth/github/callback should accept a get request and call passport.authenticate for github with a failure redirect to home'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589a69f5f9fc0f352b528e71",
"title": "Implementation of Social Authentication II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The last part of setting up your Github authentication is to create the strategy itself. For this, you will need to add the dependency of 'passport-github' to your project and require it as GithubStrategy like <code>const GitHubStrategy = require('passport-github').Strategy;</code>.",
"To set up the Github strategy, you have to tell <b>passport</b> to <b>use</b> an instantiated <b>GithubStrategy</b>, which accepts 2 arguments: An object (containing <em>clientID</em>, <em>clientSecret</em>, and <em>callbackURL</em>) and a function to be called when a user is successfully authenticated which we will determine if the user is new and what fields to save initially in the user's database object. This is common across many strategies but some may require more information as outlined in that specific strategy's github README; for example, Google requires a <em>scope</em> as well which determines what kind of information your request is asking returned and asks the user to approve such access. The current strategy we are implementing has its usage outlined <a>here</a>, but we're going through it all right here on freeCodeCamp!",
"Here's how your new strategy should look at this point: <pre>passport.use(new GitHubStrategy({\n clientID: process.env.GITHUB_CLIENT_ID,\n clientSecret: process.env.GITHUB_CLIENT_SECRET,\n callbackURL: /*INSERT CALLBACK URL ENTERED INTO GITHUB HERE*/\n },\n function(accessToken, refreshToken, profile, cb) {\n console.log(profile);\n //Database logic here with callback containing our user object\n }\n));</pre>",
"Your authentication won't be successful yet, and actually throw an error, without the database logic and callback, but it should log to your console your Github profile if you try it!",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Dependency added",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport-github', 'Your project should list \"passport-github\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Dependency required",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /require.*(\"|')passport-github(\"|')/gi, 'You should have required passport-github'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Github strategy setup correctly thus far",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /passport.use.*new GitHubStrategy/gi, 'Passport should use a new GitHubStrategy'); assert.match(data, /callbackURL:( |)(\"|').*(\"|')/gi, 'You should have a callbackURL'); assert.match(data, /process.env.GITHUB_CLIENT_SECRET/g, 'You should use process.env.GITHUB_CLIENT_SECRET'); assert.match(data, /process.env.GITHUB_CLIENT_ID/g, 'You should use process.env.GITHUB_CLIENT_ID'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589a8eb3f9fc0f352b528e72",
"title": "Implementation of Social Authentication III",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socialauth/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socialauth/'>GitHub</a>.",
"The final part of the strategy is handling the profile returned from Github. We need to load the users database object if it exists or create one if it doesn't and populate the fields from the profile, then return the user's object. Github supplies us a unique <em>id</em> within each profile which we can use to search with to serialize the user with (already implemented). Below is an example implementation you can use in your project- it goes within the function that is the second argument for the new strategy, right below the <code>console.log(profile);</code> currently is:",
"<pre>db.collection('socialusers').findAndModify(\n {id: profile.id},\n {},\n {$setOnInsert:{\n id: profile.id,\n name: profile.displayName || 'John Doe',\n photo: profile.photos[0].value || '',\n email: profile.emails[0].value || 'No public email',\n created_on: new Date(),\n provider: profile.provider || ''\n },$set:{\n last_login: new Date()\n },$inc:{\n login_count: 1\n }},\n {upsert:true, new: true},\n (err, doc) => {\n return cb(null, doc.value);\n }\n);</pre>",
"With a findAndModify, it allows you to search for an object and update it, as well as upsert the object if it doesn't exist and receive the new object back each time in our callback function. In this example, we always set the last_login as now, we always increment the login_count by 1, and only when we insert a new object(new user) do we populate the majority of the fields. Something to notice also is the use of default values. Sometimes a profile returned won't have all the information filled out or it will have been chosen by the user to remain private; so in this case we have to handle it to prevent an error.",
"You should be able to login to your app now- try it! Submit your page when you think you've got it right. If you're running into errors, you can check out an example of this mini-project's finished code <a href='https://glitch.com/#!/project/guttural-birch'>here</a>."
],
"tests": [
{
"text": "Github strategy setup complete",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /GitHubStrategy[^]*db.collection/gi, 'Strategy should use now use the database to search for the user'); assert.match(data, /GitHubStrategy[^]*socialusers/gi, 'Strategy should use \"socialusers\" as db collection'); assert.match(data, /GitHubStrategy[^]*return cb/gi, 'Strategy should return the callback function \"cb\"'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc830f9fc0f352b528e74",
"title": "Set up the Environment",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Add Socket.IO as a dependency and require/instantiate it in your server defined as 'io' with the http server as an argument. <code>const io = require('socket.io')(http);</code>",
"The first thing needing to be handled is listening for a new connection from the client. The <dfn>on</dfn> keyword does just that- listen for a specific event. It requires 2 arguments: a string containing the title of the event thats emitted, and a function with which the data is passed though. In the case of our connection listener, we use <em>socket</em> to define the data in the second argument. A socket is an individual client who is connected.",
"For listening for connections on our server, add the following between the comments in your project:<pre>io.on('connection', socket => {\n console.log('A user has connected');\n});</pre>",
"Now for the client to connect, you just need to add the following to your client.js which is loaded by the page after you've authenticated: <pre>/*global io*/\nvar socket = io();</pre>The comment suppresses the error you would normally see since 'io' is not defined in the file. We've already added a reliable CDN to the Socket.IO library on the page in chat.pug.",
"Now try loading up your app and authenticate and you should see in your server console 'A user has connected'!",
"<strong>Note</strong><br><code>io()</code> works only when connecting to a socket hosted on the same url/server. For connecting to an external socket hosted elsewhere, you would use <code>io.connect('URL');</code>.",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Socket.IO is a dependency",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'socket.io', 'Your project should list \"socket.io\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Socket.IO has been properly required and instanciated",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /io.*=.*require.*('|\")socket.io('|\").*http/gi, 'You should correctly require and instantiate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Socket.IO should be listening for connections",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.on.*('|\")connection('|\").*socket/gi, 'io should listen for \"connection\" and socket should be the 2nd arguments variable'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client should connect to your server",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.*=.*io/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e75",
"title": "Communicate by Emitting",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"<dfn>Emit</dfn> is the most common way of communicating you will use. When you emit something from the server to 'io', you send an event's name and data to all the connected sockets. A good example of this concept would be emitting the current count of connected users each time a new user connects!",
"<hr>Start by adding a variable to keep track of the users just before where you are currently listening for connections. <code>var currentUsers = 0;</code>",
"Now when someone connects you should increment the count before emitting the count so you will want to add the incrementer within the connection listener. <code>++currentUsers;</code>",
"Finally after incrementing the count, you should emit the event(still within the connection listener). The event should be named 'user count' and the data should just be the 'currentUsers'. <code>io.emit('user count', currentUsers);</code>",
"<hr>Now you can implement a way for your client to listen for this event! Similarly to listening for a connection on the server you will use the <em>on</em> keyword. <pre>socket.on('user count', function(data){\n console.log(data);\n});</pre>",
"Now try loading up your app and authenticate and you should see in your client console '1' representing the current user count! Try loading more clients up and authenticating to see the number go up.",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "currentUsers is defined",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /currentUsers/gi, 'You should have variable currentUsers defined');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Server emits the current user count at each new connection",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|\")user count('|\").*currentUsers/gi, 'You should emit \"user count\" with data currentUsers'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client is listening for 'user count' event",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user count('|\")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e76",
"title": "Handle a Disconnect",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"You may notice that up to now you have only been increasing the user count. Handling a user disconnecting is just as easy as handling the initial connect except the difference is you have to listen for it on each socket versus on the whole server.",
"<hr>To do this, add in to your existing connect listener a listener that listens for 'disconnect' on the socket with no data passed through. You can test this functionality by just logging to the console a user has disconnected. <code>socket.on('disconnect', () => { /*anything you want to do on disconnect*/ });</code>",
"To make sure clients continuously have the updated count of current users, you should decrease the currentUsers by 1 when the disconnect happens then emit the 'user count' event with the updated count!",
"<strong>Note</strong><br>Just like 'disconnect', all other events that a socket can emit to the server should be handled within the connecting listener where we have 'socket' defined.",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Server handles the event disconnect from a socket",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|\")disconnect('|\")/gi, ''); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "Your client is listening for 'user count' event",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user count('|\")/gi, 'Your client should be connection to server with the connection defined as socket'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc831f9fc0f352b528e77",
"title": "Authentication with Socket.IO",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Currently, you cannot determine who is connected to your web socket. While 'req.user' containers the user object, thats only when your user interacts with the web server and with web sockets you have no req (request) and therefor no user data. One way to solve the problem of knowing who is connected to your web socket is by parsing and decoding the cookie that contains the passport session then deserializing it to obtain the user object. Luckily, there is a package on NPM just for this that turns a once complex task into something simple!",
"<hr>Add 'passport.socketio' as a dependency and require it as 'passportSocketIo'.",
"Now we just have to tell Socket.IO to use it and set the options. Be sure this is added before the existing socket code and not in the existing connection listener. For your server it should look as follows:<pre>io.use(passportSocketIo.authorize({\n cookieParser: cookieParser,\n key: 'express.sid',\n secret: process.env.SESSION_SECRET,\n store: sessionStore\n}));</pre>You can also optionally pass 'success' and 'fail' with a function that will be called after the authentication process completes when a client trys to connect.",
"The user object is now accessible on your socket object as <code>socket.request.user</code>. For example, now you can add the following: <code>console.log('user ' + socket.request.user.name + ' connected');</code> and it will log to the server console who has connected!",
"Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/a9e69ff91337500d5171e29324e1ff35'>here</a>."
],
"tests": [
{
"text": "passportSocketIo is a dependency",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'passport.socketio', 'Your project should list \"passport.socketio\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "passportSocketIo is properly required",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => { assert.match(data, /require\\((['\"])passport\\.socketio\\1\\)/gi, 'You should correctly require and instantiate \"passport.socketio\"');}, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "passportSocketIo is properly setup",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io\\.use\\(.+\\.authorize\\(/gi, 'You should register \"passport.socketio\" as socket.io middleware and provide it correct options'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc832f9fc0f352b528e78",
"title": "Announce New Users",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"Many chat rooms are able to annouce when a user connects or disconnects and then display that to all of the connected users in the chat. Seeing as though you already are emitting an event on connect and disconnect, you will just have to modify this event to support such feature. The most logical way of doing so is sending 3 pieces of data with the event: name of the user connected/disconnected, the current user count, and if that name connected or disconnected.",
"<hr>Change the event name to 'user' and as the data pass an object along containing fields 'name', 'currentUsers', and boolean 'connected' (to be true if connection, or false for disconnection of the user sent). Be sure to make the change to both points we had the 'user count' event and set the disconnect one to sent false for field 'connected' instead of true like the event emitted on connect. <code>io.emit('user', {name: socket.request.user.name, currentUsers, connected: true});</code>",
"Now your client will have all the nesesary information to correctly display the current user count and annouce when a user connects or disconnects! To handle this event on the client side we should listen for 'user' and then update the current user count by using jQuery to change the text of <code>#num-users</code> to '{NUMBER} users online', as well as append a <code>&#60;li&#62;</code> to the unordered list with id 'messages' with '{NAME} has {joined/left} the chat.'.",
"An implementation of this could look like the following:<pre>socket.on('user', function(data){\n $('#num-users').text(data.currentUsers+' users online');\n var message = data.name;\n if(data.connected) {\n message += ' has joined the chat.';\n } else {\n message += ' has left the chat.';\n }\n $('#messages').append($('&#60;li&#62;').html('&#60;b&#62;'+ message +'&#60;\\/b&#62;'));\n});</pre>",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text":
"Event 'user' is emitted with name, currentUsers, and connected",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /io.emit.*('|\")user('|\").*name.*currentUsers.*connected/gi, 'You should have an event emitted named user sending name, currentUsers, and connected'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text":
"Client properly handling and displaying the new data from event 'user'",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")user('|\")[^]*num-users/gi, 'You should change the text of #num-users within on your client within the \"user\" even listener to show the current users connected'); assert.match(data, /socket.on.*('|\")user('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"user\" event listener to annouce a user came or went'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
},
{
"id": "589fc832f9fc0f352b528e79",
"title": "Send and Display Chat Messages",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-socketio/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-socketio/'>GitHub</a>.",
"It's time you start allowing clients to send a chat message to the server to emit to all the clients! Already in your client.js file you should see there is already a block of code handling when the messgae form is submitted! (<code>$('form').submit(function(){ /*logic*/ });</code>)",
"<hr>Within the code you're handling the form submit you should emit an event after you define 'messageToSend' but before you clear the text box <code>#m</code>. The event should be named 'chat message' and the data should just be 'messageToSend'. <code>socket.emit('chat message', messageToSend);</code>",
"Now on your server you should be listening to the socket for the event 'chat message' with the data being named 'message'. Once the event is received it should then emit the event 'chat message' to all sockets <code>io.emit</code> with the data being an object containing 'name' and 'message'.",
"On your client now again, you should now listen for event 'chat message' and when received, append a list item to <code>#messages</code> with the name a colon and the message!",
"At this point the chat should be fully functional and sending messages across all clients! Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point <a href='https://gist.github.com/JosephLivengood/3e4b7750f6cd42feaa2768458d682136'>here for the server</a> and <a href='https://gist.github.com/JosephLivengood/41ba76348df3013b7870dc64861de744'>here for the client</a>."
],
"tests": [
{
"text": "Server listens for 'chat message' then emits it properly",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /socket.on.*('|\")chat message('|\")[^]*io.emit.*('|\")chat message('|\").*name.*message/gi, 'Your server should listen to the socket for \"chat message\" then emit to all users \"chat message\" with name and message in the data object'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text":
"Client properly handling and displaying the new data from event 'chat message'",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/public/client.js') .then(data => { assert.match(data, /socket.on.*('|\")chat message('|\")[^]*messages.*li/gi, 'You should append a list item to #messages on your client within the \"chat message\" event listener to display the new message'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"translations": {}
}
]
}

View File

@ -0,0 +1,347 @@
{
"name": "Information Security with HelmetJS",
"order": 1,
"time": "5 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "587d8247367417b2b2512c36",
"title": "Install and Require Helmet",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Helmet helps you secure your Express apps by setting various HTTP headers. Install the package, then require it."
],
"tests": [
{
"text": "\"helmet\" dependency should be in package.json",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/package.json').then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'helmet'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8247367417b2b2512c37",
"title":
"Hide Potentially Dangerous Information Using helmet.hidePoweredBy()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Hackers can exploit known vulnerabilities in Express/Node if they see that your site is powered by Express. X-Powered-By: Express is sent in every request coming from Express by default. The helmet.hidePoweredBy() middleware will remove the X-Powered-By header. You can also explicitly set the header to something else, to throw people off. e.g. app.use(helmet.hidePoweredBy({ setTo: 'PHP 4.2.0' }))"
],
"tests": [
{
"text":
"helmet.hidePoweredBy() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hidePoweredBy'); assert.notEqual(data.headers['x-powered-by'], 'Express')}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8247367417b2b2512c38",
"title": "Mitigate the Risk of Clickjacking with helmet.frameguard()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Your page could be put in a <code>&lt;frame&gt;</code> or <code>&lt;iframe&gt;</code> without your consent. This can result in clickjacking attacks, among other things. Clickjacking is a technique of tricking a user into interacting with a page different from what the user thinks it is. This can be obtained executing your page in a malicious context, by mean of iframing. In that context a hacker can put a hidden layer over your page. Hidden buttons can be used to run bad scripts. This middleware sets the X-Frame-Options header. It restricts who can put your site in a frame. It has three modes: DENY, SAMEORIGIN, and ALLOW-FROM.",
"We dont need our app to be framed. You should use <code>helmet.frameguard()</code> passing with the configuration object <code>{action: 'deny'}</code>."
],
"tests": [
{
"text": "helmet.frameguard() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'frameguard', 'helmet.frameguard() middleware is not mounted correctly'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "helmet.frameguard() 'action' should be set to 'DENY'",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.property(data.headers, 'x-frame-options'); assert.equal(data.headers['x-frame-options'], 'DENY');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8247367417b2b2512c39",
"title":
"Mitigate the Risk of Cross Site Scripting (XSS) Attacks with helmet.xssFilter()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Cross-site scripting (XSS) is a frequent type of attack where malicious scripts are injected into vulnerable pages, with the purpose of stealing sensitive data like session cookies, or passwords.",
"The basic rule to lower the risk of an XSS attack is simple: “Never trust users input”. As a developer you should always sanitize all the input coming from the outside. This includes data coming from forms, GET query urls, and even from POST bodies. Sanitizing means that you should find and encode the characters that may be dangerous e.g. <, >.",
"Modern browsers can help mitigating the risk by adopting better software strategies. Often these are configurable via http headers.",
"The X-XSS-Protection HTTP header is a basic protection. The browser detects a potential injected script using a heuristic filter. If the header is enabled, the browser changes the script code, neutralizing it.",
"It still has limited support."
],
"tests": [
{
"text": "helmet.xssFilter() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'xXssProtection'); assert.property(data.headers, 'x-xss-protection'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8248367417b2b2512c3a",
"title": "Avoid Inferring the Response MIME Type with helmet.noSniff()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Browsers can use content or MIME sniffing to adapt to different datatypes coming from a response. They override the Content-Type headers to guess and process the data. While this can be convenient in some scenarios, it can also lead to some dangerous attacks. This middleware sets the X-Content-Type-Options header to nosniff. This instructs the browser to not bypass the provided Content-Type."
],
"tests": [
{
"text": "helmet.noSniff() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nosniff'); assert.equal(data.headers['x-content-type-options'], 'nosniff'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8248367417b2b2512c3b",
"title": "Prevent IE from Opening Untrusted HTML with helmet.ieNoOpen()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"Some web applications will serve untrusted HTML for download. Some versions of Internet Explorer by default open those HTML files in the context of your site. This means that an untrusted HTML page could start doing bad things in the context of your pages. This middleware sets the X-Download-Options header to noopen. This will prevent IE users from executing downloads in the trusted sites context."
],
"tests": [
{
"text": "helmet.ieNoOpen() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'ienoopen'); assert.equal(data.headers['x-download-options'], 'noopen'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8248367417b2b2512c3c",
"title":
"Ask Browsers to Access Your Site via HTTPS Only with helmet.hsts()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"HTTP Strict Transport Security (HSTS) is a web security policy which helps to protect websites against protocol downgrade attacks and cookie hijacking. If your website can be accessed via HTTPS you can ask users browsers to avoid using insecure HTTP. By setting the header Strict-Transport-Security, you tell the browsers to use HTTPS for the future requests in a specified amount of time. This will work for the requests coming after the initial request.",
"Configure helmet.hsts() to use HTTPS for the next 90 days. Pass the config object {maxAge: timeInMilliseconds, force: true}. Glitch already has hsts enabled. To override its settings you need to set the field \"force\" to true in the config object. We will intercept and restore the Glitch header, after inspecting it for testing.",
"Note: Configuring HTTPS on a custom website requires the acquisition of a domain, and a SSL/TSL Certificate."
],
"tests": [
{
"text": "helmet.hsts() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'hsts'); assert.property(data.headers, 'strict-transport-security'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "maxAge should be equal to 7776000 ms (90 days)",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.match(data.headers['strict-transport-security'], /^max-age=777600000;?/); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8248367417b2b2512c3d",
"title": "Disable DNS Prefetching with helmet.dnsPrefetchControl()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"To improve performance, most browsers prefetch DNS records for the links in a page. In that way the destination ip is already known when the user clicks on a link. This may lead to over-use of the DNS service (if you own a big website, visited by millions people…), privacy issues (one eavesdropper could infer that you are on a certain page), or page statistics alteration (some links may appear visited even if they are not). If you have high security needs you can disable DNS prefetching, at the cost of a performance penalty."
],
"tests": [
{
"text":
"helmet.dnsPrefetchControl() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'dnsPrefetchControl'); assert.equal(data.headers['x-dns-prefetch-control'], 'off'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8249367417b2b2512c3e",
"title": "Disable Client-Side Caching with helmet.noCache()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"If you are releasing an update for your website, and you want the users to always download the newer version, you can (try to) disable caching on clients browser. It can be useful in development too. Caching has performance benefits, which you will lose, so only use this option when there is a real need."
],
"tests": [
{
"text": "helmet.noCache() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'nocache'); assert.equal(data.headers['cache-control'], 'no-store, no-cache, must-revalidate, proxy-revalidate'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8249367417b2b2512c3f",
"title":
"Set a Content Security Policy with helmet.contentSecurityPolicy()",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"This challenge highlights one promising new defense that can significantly reduce the risk and impact of many type of attacks in modern browsers. By setting and configuring a Content Security Policy you can prevent the injection of anything unintended into your page. This will protect your app from XSS vulnerabilities, undesired tracking, malicious frames, and much more. CSP works by defining a whitelist of content sources which are trusted. You can configure them for each kind of resource a web page may need (scripts, stylesheets, fonts, frames, media, and so on…). There are multiple directives available, so a website owner can have a granular control. See HTML 5 Rocks, KeyCDN for more details. Unfortunately CSP is unsupported by older browser.",
"By default, directives are wide open, so its important to set the defaultSrc directive as a fallback. Helmet supports both defaultSrc and default-src naming styles. The fallback applies for most of the unspecified directives. In this exercise, use helmet.contentSecurityPolicy(), and configure it setting the defaultSrc directive to [\"self\"] (the list of allowed sources must be in an array), in order to trust only your website address by default. Set also the scriptSrc directive so that you will allow scripts to be downloaded from your website, and from the domain 'trusted-cdn.com'.",
"Hint: in the \"'self'\" keyword, the single quotes are part of the keyword itself, so it needs to be enclosed in double quotes to be working."
],
"tests": [
{
"text": "helmet.csp() middleware should be mounted correctly",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { assert.include(data.appStack, 'csp'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text":
"Your csp config is not correct. defaultSrc should be [\"'self'\"] and scriptSrc should be [\"'self'\", 'trusted-cdn.com']",
"testString":
"getUserInput => $.get(getUserInput('url') + '/_api/app-info').then(data => { var cspHeader = Object.keys(data.headers).filter(function(k){ return k === 'content-security-policy' || k === 'x-webkit-csp' || k === 'x-content-security-policy' })[0]; assert.equal(data.headers[cspHeader], \"default-src 'self'; script-src 'self' trusted-cdn.com\"); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8249367417b2b2512c40",
"title": "Configure Helmet Using the parent helmet() Middleware",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-infosec/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-infosec/'>GitHub</a>.",
"app.use(helmet()) will automatically include all the middleware introduced above, except noCache(), and contentSecurityPolicy(), but these can be enabled if necessary. You can also disable or configure any other middleware individually, using a configuration object.",
"// Example",
"<code>app.use(helmet({</code>",
"<code> frameguard: { // configure</code>",
"<code> action: 'deny'</code>",
"<code> },</code>",
"<code> contentSecurityPolicy: { // enable and configure</code>",
"<code> directives: {</code>",
"<code> defaultSrc: [\"self\"],</code>",
"<code> styleSrc: ['style.com'],</code>",
"<code> }</code>",
"<code> },</code>",
"<code> dnsPrefetchControl: false // disable</code>",
"<code>}))</code>",
"We introduced each middleware separately for teaching purpose, and for ease of testing. Using the parent helmet() middleware is easiest, and cleaner, for a real project."
],
"tests": [
{
"text": "no tests - it's a descriptive challenge",
"testString": "assert(true)"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "58a25bcef9fc0f352b528e7c",
"title": "Understand BCrypt Hashes",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"BCrypt hashes are very secure. A hash is basically a fingerprint of the original data- always unique. This is accomplished by feeding the original data into a algorithm and having returned a fixed length result. To further complicate this process and make it more secure, you can also <em>salt</em> your hash. Salting your hash involves adding random data to the original data before the hashing process which makes it even harder to crack the hash.",
"BCrypt hashes will always looks like <code>$2a$13$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm</code> which does have a structure. The first small bit of data <code>$2a</code> is defining what kind of hash algorithm was used. The next portion <code>$13</code> defines the <em>cost</em>. Cost is about how much power it takes to compute the hash. It is on a logarithmic scale of 2^cost and determines how many times the data is put through the hashing algorithm. For example, at a cost of 10 you are able to hash 10 passwords a second on an average computer, however at a cost of 15 it takes 3 seconds per hash... and to take it further, at a cost of 31 it would takes multiple days to complete a hash. A cost of 12 is considered very secure at this time. The last portion of your hash <code>$ZyprE5MRw2Q3WpNOGZWGbeG7ADUre1Q8QO.uUUtcbqloU0yvzavOm</code>, looks like 1 large string of numbers, periods, and letters but it is actually 2 separate pieces of information. The first 22 characters is the salt in plain text, and the rest is the hashed password!",
"<hr>To begin using BCrypt, add it as a dependency in your project and require it as 'bcrypt' in your server.",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "BCyrpt is a dependency",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/package.json') .then(data => { var packJson = JSON.parse(data); assert.property(packJson.dependencies, 'bcrypt', 'Your project should list \"bcrypt\" as a dependency'); }, xhr => { throw new Error(xhr.statusText); })"
},
{
"text": "BCrypt has been properly required",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js').then(data => {assert.match(data, /bcrypt.*=.*require.*('|\")bcrypt('|\")/gi, 'You should correctly require and instantiate socket.io as io.');}, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "58a25bcff9fc0f352b528e7d",
"title": "Hash and Compare Passwords Asynchronously",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"As hashing is designed to be computationally intensive, it is recommended to do so asyncronously on your server as to avoid blocking incoming connections while you hash. All you have to do to hash a password asynchronous is call <code>bcrypt.hash(myPlaintextPassword, saltRounds, (err, hash) => { /*Store hash in your db*/ });</code>",
"<hr>Add this hashing function to your server(we've already defined the variables used in the function for you to use) and log it to the console for you to see! At this point you would normally save the hash to your database.",
"Now when you need to figure out if a new input is the same data as the hash you would just use the compare function <code>bcrypt.compare(myPlaintextPassword, hash, (err, res) => { /*res == true or false*/ });</code>. Add this into your existing hash function(since you need to wait for the hash to complete before calling the compare function) after you log the completed hash and log 'res' to the console within the compare. You should see in the console a hash then 'true' is printed! If you change 'myPlaintextPassword' in the compare function to 'someOtherPlaintextPassword' then it should say false.",
"<pre>bcrypt.hash('passw0rd!', 13, (err, hash) => {\n console.log(hash); //$2a$12$Y.PHPE15wR25qrrtgGkiYe2sXo98cjuMCG1YwSI5rJW1DSJp0gEYS\n bcrypt.compare('passw0rd!', hash, (err, res) => {\n console.log(res); //true\n });\n});</pre>",
"Submit your page when you think you've got it right."
],
"tests": [
{
"text": "Async hash generated and correctly compared",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_ASYNC[^]*bcrypt.hash.*myPlaintextPassword( |),( |)saltRounds( |),( |).*err( |),( |)hash[^]*END_ASYNC/gi, 'You should call bcrypt.hash on myPlaintextPassword and saltRounds and handle err and hash as a result in the callback'); assert.match(data, /START_ASYNC[^]*bcrypt.hash[^]*bcrypt.compare.*myPlaintextPassword( |),( |)hash( |),( |).*err( |),( |)res[^]*}[^]*}[^]*END_ASYNC/gi, 'Nested within the hash function should be the compare function comparing myPlaintextPassword to hash'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "58a25bcff9fc0f352b528e7e",
"title": "Hash and Compare Passwords Synchronously",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-bcrypt/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-bcrypt/'>GitHub</a>.",
"Hashing synchronously is just as easy to do but can cause lag if using it server side with a high cost or with hashing done very often. Hashing with this method is as easy as calling <code>var hash = bcrypt.hashSync(myPlaintextPassword, saltRounds);</code>",
"<hr>Add this method of hashing to your code and then log the result to the console. Again, the variables used are already defined in the server so you wont need to adjust them. You may notice even though you are hashing the same password as in the async function, the result in the console is different- this is due to the salt being randomly generated each time as seen by the first 22 characters in the third string of the hash.",
"Now to compare a password input with the new sync hash, you would use the compareSync method: <code>var result = bcrypt.compareSync(myPlaintextPassword, hash);</code> with the result being a boolean true or false. Add this function in and log to the console the result to see it working.",
"Submit your page when you think you've got it right. If you ran into errors during these challenges you can take a look at the example completed code <a href='https://gist.github.com/JosephLivengood/9a2698fb63e42d9d8b4b84235c08b4c4'>here</a>."
],
"tests": [
{
"text": "Sync hash generated and correctly compared",
"testString":
"getUserInput => $.get(getUserInput('url')+ '/_api/server.js') .then(data => { assert.match(data, /START_SYNC[^]*hash.*=.*bcrypt.hashSync.*myPlaintextPassword( |),( |)saltRounds[^]*END_SYNC/gi, 'You should call bcrypt.hashSync on myPlaintextPassword with saltRounds'); assert.match(data, /START_SYNC[^]*result.*=.*bcrypt.compareSync.*myPlaintextPassword( |),( |)hash[^]*END_SYNC/gi, 'You should call bcrypt.compareSync on myPlaintextPassword with the hash generated in the last line'); }, xhr => { throw new Error(xhr.statusText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
}
]
}

View File

@ -0,0 +1,293 @@
{
"name": "Information Security and Quality Assurance Projects",
"order": 4,
"time": "150 hours",
"helpRoom": "HelpBackend",
"challenges": [
{
"id": "587d8249367417b2b2512c41",
"title": "Metric-Imperial Converter",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://hard-twilight.glitch.me/' target='_blank'>https://hard-twilight.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-metricimpconverter/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "I will prevent the client from trying to guess(sniff) the MIME type.",
"testString": ""
},
{
"text": "I will prevent cross-site scripting (XSS) attacks.",
"testString": ""
},
{
"text": "I can GET /api/convert with a single parameter containing an accepted number and unit and have it converted. (Hint: Split the input by looking for the index of the first character which will mark the start of the unit)",
"testString": ""
},
{
"text": "I can convert 'gal' to 'L' and vice versa. (1 gal to 3.78541 L)",
"testString": ""
},
{
"text": "I can convert 'lbs' to 'kg' and vice versa. (1 lbs to 0.453592 kg)",
"testString": ""
},
{
"text": "I can convert 'mi' to 'km' and vice versa. (1 mi to 1.60934 km)",
"testString": ""
},
{
"text": "If my unit of measurement is invalid, returned will be 'invalid unit'.",
"testString": ""
},
{
"text": "If my number is invalid, returned with will 'invalid number'.",
"testString": ""
},
{
"text": "If both are invalid, return will be 'invalid number and unit'.",
"testString": ""
},
{
"text": "I can use fractions, decimals or both in my parameter(ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.",
"testString": ""
},
{
"text": "My return will consist of the initNum, initUnit, returnNum, returnUnit, and string spelling out units in format '{initNum} {initial_Units} converts to {returnNum} {return_Units}' with the result rounded to 5 decimals in the string.",
"testString": ""
},
{
"text": "All 16 unit tests are complete and passing.",
"testString": ""
},
{
"text": "All 5 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d8249367417b2b2512c42",
"title": "Issue Tracker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://protective-garage.glitch.me/' target='_blank'>https://protective-garage.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-issuetracker/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-issuetracker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "Prevent cross site scripting (XSS) attacks.",
"testString": ""
},
{
"text": "I can POST /api/issues/{projectname} with form data containing required issue_title, issue_text, created_by, and optional assigned_to and status_text.",
"testString": ""
},
{
"text": "The object saved (and returned) will include all of those fields (blank for optional no input) and also include created_on(date/time), updated_on(date/time), open(boolean, true for open, false for closed), and _id.",
"testString": ""
},
{
"text": "I can PUT /api/issues/{projectname} with a id and any fields in the object with a value to object said object. Returned will be 'successfully updated' or 'could not update '+id. This should always update updated_on. If no fields are sent return 'no updated field sent'.",
"testString": ""
},
{
"text": "I can DELETE /api/issues/{projectname} with a id to completely delete an issue. If no _id is sent return 'id error', success: 'deleted '+id, failed: 'could not delete '+id.",
"testString": ""
},
{
"text": "I can GET /api/issues/{projectname} for an array of all issues on that specific project with all the information for each issue as was returned when posted.",
"testString": ""
},
{
"text": "I can filter my get request by also passing along any field and value in the query(ie. /api/issues/{project}?open=false). I can pass along as many fields/values as I want.",
"testString": ""
},
{
"text": "All 11 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c43",
"title": "Personal Library",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://spark-cathedral.glitch.me/' target='_blank'>https://spark-cathedral.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-library/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-library/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "Nothing from my website will be cached in my client.",
"testString": ""
},
{
"text": "The headers will say that the site is powered by 'PHP 4.2.0' even though it isn't (as a security measure).",
"testString": ""
},
{
"text": "I can post a title to /api/books to add a book and returned will be the object with the title and a unique _id.",
"testString": ""
},
{
"text": "I can get /api/books to retrieve an array of all books containing title, _id, and commentcount.",
"testString": ""
},
{
"text": "I can get /api/books/{id} to retrieve a single object of a book containing _title, _id, & an array of comments (empty array if no comments present).",
"testString": ""
},
{
"text": "I can post a comment to /api/books/{id} to add a comment to a book and returned will be the books object similar to get /api/books/{id} including the new comment.",
"testString": ""
},
{
"text": "I can delete /api/books/{_id} to delete a book from the collection. Returned will be 'delete successful' if successful.",
"testString": ""
},
{
"text": "If I try to request a book that doesn't exist I will be returned 'no book exists'.",
"testString": ""
},
{
"text": "I can send a delete request to /api/books to delete all books in the database. Returned will be 'complete delete successful' if successful.",
"testString": ""
},
{
"text": "All 6 functional tests required are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c44",
"title": "Stock Price Checker",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://giant-chronometer.glitch.me/' target='_blank'>https://giant-chronometer.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-stockchecker/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-stockchecker/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "Set the content security policies to only allow loading of scripts and css from your server.",
"testString": ""
},
{
"text": "I can GET /api/stock-prices with form data containing a Nasdaq stock ticker and receive back an object stockData.",
"testString": ""
},
{
"text": "In stockData, I can see the stock(string, the ticker), price(decimal in string format), and likes(int).",
"testString": ""
},
{
"text": "I can also pass along field like as true(boolean) to have my like added to the stock(s). Only 1 like per ip should be accepted.",
"testString": ""
},
{
"text": "If I pass along 2 stocks, the return object will be an array with both stock's info. Instead of likes, it will display rel_likes(the difference between the likes on both stocks) on both.",
"testString": ""
},
{
"text": "A good way to receive current price is the following external API(replacing 'GOOG' with your stock): https://finance.google.com/finance/info?q=NASDAQ%3aGOOG",
"testString": ""
},
{
"text": "All 5 functional tests are complete and passing.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
},
{
"id": "587d824a367417b2b2512c45",
"title": "Anonymous Message Board",
"description": [
"Build a full stack JavaScript app that is functionally similar to this: <a href='https://horn-celery.glitch.me/' target='_blank'>https://horn-celery.glitch.me/</a>.",
"Working on this project will involve you writing your code on Glitch on our starter project. After completing this project you can copy your public glitch url (to the homepage of your app) into this screen to test it! Optionally you may choose to write your project on another platform but it must be publicly visible for our testing.",
"Start this project on Glitch using <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-project-messageboard/'>this link</a> or clone <a href='https://github.com/freeCodeCamp/boilerplate-project-messageboard/'>this repository</a> on GitHub! If you use Glitch, remember to save the link to your project somewhere safe!"
],
"tests": [
{
"text": "Only allow your site to be loading in an iFrame on your own pages.",
"testString": ""
},
{
"text": "Do not allow DNS prefetching.",
"testString": ""
},
{
"text": "Only allow your site to send the referrer for your own pages.",
"testString": ""
},
{
"text": "I can POST a thread to a specific message board by passing form data text and deletepassword_ to /api/threads/{board}.(Recommend res.redirect to board page /b/{board}) Saved will be at least _id, text, createdon_(date&time), bumpedon_(date&time, starts same as created_on), reported(boolean), deletepassword_, & replies(array).",
"testString": ""
},
{
"text": "I can POST a reply to a thread on a specific board by passing form data text, deletepassword_, & threadid_ to /api/replies/{board} and it will also update the bumped_on date to the comments date.(Recommend res.redirect to thread page /b/{board}/{thread_id}) In the thread's replies array will be saved _id, text, createdon_, deletepassword_, & reported.",
"testString": ""
},
{
"text": "I can GET an array of the most recent 10 bumped threads on the board with only the most recent 3 replies each from /api/threads/{board}. The reported and deletepasswords_ fields will not be sent to the client.",
"testString": ""
},
{
"text": "I can GET an entire thread with all its replies from /api/replies/{board}?thread_id={thread_id}. Also hiding the same fields the client should be see.",
"testString": ""
},
{
"text": "I can delete a thread completely if I send a DELETE request to /api/threads/{board} and pass along the threadid_ & deletepassword_. (Text response will be 'incorrect password' or 'success')",
"testString": ""
},
{
"text": "I can delete a post(just changing the text to '[deleted]' instead of removing completely like a thread) if I send a DELETE request to /api/replies/{board} and pass along the threadid_, replyid_, & deletepassword_. (Text response will be 'incorrect password' or 'success')",
"testString": ""
},
{
"text": "I can report a thread and change its reported value to true by sending a PUT request to /api/threads/{board} and pass along the threadid_. (Text response will be 'success')",
"testString": ""
},
{
"text": "I can report a reply and change its reported value to true by sending a PUT request to /api/replies/{board} and pass along the threadid_ & replyid_. (Text response will be 'success')",
"testString": ""
},
{
"text": "Complete functional tests that wholly test routes and pass.",
"testString": ""
}
],
"solutions": [],
"hints": [],
"challengeType": 4,
"isRequired": true,
"releasedOn": "January 15, 2017",
"translations": {}
}
]
}

View File

@ -0,0 +1,791 @@
{
"name": "Quality Assurance and Testing with Chai",
"order": 2,
"time": "5 hours",
"helpRoom": "Help",
"challenges": [
{
"id": "587d824a367417b2b2512c46",
"title": "Learn How JavaScript Assertions Work",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isNull() or assert.isNotNull() to make the tests pass."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isNull vs. isNotNull",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => { assert.equal(data.assertions[0].method, 'isNull', 'Null is null'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isNull vs. isNotNull",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=0').then(data => { assert.equal(data.assertions[1].method, 'isNotNull', '1 is not null'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824b367417b2b2512c47",
"title": "Test if a Variable or Function is Defined",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isDefined() or assert.isUndefined() to make the tests pass"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[0].method, 'isDefined', 'Null is not undefined'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[1].method, 'isUndefined', 'Undefined is undefined'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isDefined vs. isUndefined",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=1').then(data => { assert.equal(data.assertions[2].method, 'isDefined', 'A string is not undefined'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824b367417b2b2512c48",
"title": "Use Assert.isOK and Assert.isNotOK",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isOk() or assert.isNotOk() to make the tests pass.",
".isOk(truthy) and .isNotOk(falsey) will pass."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[0].method, 'isNotOk', 'Null is falsey'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[1].method, 'isOk','A string is truthy'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isOk vs. isNotOk",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=2').then(data => { assert.equal(data.assertions[2].method, 'isOk', 'true is truthy'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824b367417b2b2512c49",
"title": "Test for Truthiness",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Use assert.isTrue() or assert.isNotTrue() to make the tests pass.",
".isTrue(true) and .isNotTrue(everything else) will pass.",
".isFalse() and .isNotFalse() also exist."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[0].method, 'isTrue', 'True is true'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[1].method, 'isTrue', 'Double negation of a truthy value is true'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isTrue vs. isNotTrue",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=3').then(data => { assert.equal(data.assertions[2].method, 'isNotTrue', 'A truthy object is not true - neither is a false one'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824b367417b2b2512c4a",
"title": "Use the Double Equals to Assert Equality",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".equal(), .notEqual()",
".equal() compares objects using '=='"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[0].method, 'equal', 'Numbers are coerced into strings with == '); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[1].method, 'notEqual', ' == compares object references'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[2].method, 'equal', '6 * \\'2\\' is 12 ! It should be equal to \\'12\\''); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - equal vs. notEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=4').then(data => { assert.equal(data.assertions[3].method, 'notEqual', '6 + \\'2\\' is \\'62\\'...'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824b367417b2b2512c4b",
"title": "Use the Triple Equals to Assert Strict Equality",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".strictEqual(), .notStrictEqual()",
".strictEqual() compares objects using '==='"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[0].method, 'notStrictEqual', 'with strictEqual the type must match'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[1].method, 'strictEqual', '3*2 = 6...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[2].method, 'strictEqual', '6 * \\'2\\' is 12. Types match !'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - strictEqual vs. notStrictEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=5').then(data => { assert.equal(data.assertions[3].method, 'notStrictEqual', 'Even if they have the same elements, the Arrays are notStrictEqual'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824c367417b2b2512c4c",
"title": "Assert Deep Equality with .deepEqual and .notDeepEqual",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".deepEqual(), .notDeepEqual()",
".deepEqual() asserts that two object are deep equal"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - deepEqual vs. notDeepEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => { assert.equal(data.assertions[0].method, 'deepEqual', 'The order of the keys does not matter'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - deepEqual vs. notDeepEqual",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=6').then(data => { assert.equal(data.assertions[1].method, 'notDeepEqual', 'The position of elements within an array does matter'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824c367417b2b2512c4d",
"title": "Compare the Properties of Two Elements",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".isAbove() => a > b , .isAtMost() => a <= b"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[0].method, 'isAtMost', '5 is at most (<=) 5'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[1].method, 'isAbove', '1 is greater than 0'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[2].method, 'isAbove', 'Math.PI = 3.14159265 is greater than 3'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isAbove vs. isAtMost",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=7').then(data => { assert.equal(data.assertions[3].method, 'isAtMost', '1 - Math.random() is > 0 and <= 1. It is atMost 1 !'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824c367417b2b2512c4e",
"title": "Test if One Value is Below or At Least as Large as Another",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".isBelow() => a < b , .isAtLeast => a >= b"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[0].method, 'isAtLeast', '5 is at least (>=) 5'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[1].method, 'isAtLeast', '2 * Math.random() is at least 0'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[2].method, 'isBelow', '1 is smaller than 2'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isBelow vs. isAtLeast",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=8').then(data => { assert.equal(data.assertions[3].method, 'isBelow', '2/3 (0.6666) is smaller than 1'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824c367417b2b2512c4f",
"title": "Test if a Value Falls within a Specific Range",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
".approximately",
".approximately(actual, expected, range, [message])",
"actual = expected +/- range",
"Choose the minimum range (3rd parameter) to make the test always pass",
"it should be less than 1"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=9').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Use approximately(actual, expected, range) - Chose the correct range",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=9').then(data => { assert.equal(data.assertions[0].method, 'approximately'); assert.equal(data.assertions[0].args[2], 0.5, 'weirdNumbers(0.5) is in the range (0.5, 1.5]. It\\'s within 1 +/- 0.5'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Use approximately(actual, expected, range) - Chose the correct range",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=9').then(data => { assert.equal(data.assertions[1].method, 'approximately'); assert.equal(data.assertions[1].args[2], 0.8, 'weirdNumbers(0.2) is in the range (0.2, 1.2]. It\\'s within 1 +/- 0.8'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824d367417b2b2512c50",
"title": "Test if a Value is an Array",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => {assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isArray vs. isNotArray",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[0].method, 'isArray', 'String.prototype.split() returns an Array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isArray vs. isNotArray",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=10').then(data => { assert.equal(data.assertions[1].method, 'isNotArray', 'Array.prototype.indexOf() returns a number'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824d367417b2b2512c51",
"title": "Test if an Array Contains an Item",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.assertions[0].method, 'notInclude', 'It\\'s summer in july...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=11').then(data => { assert.equal(data.assertions[1].method, 'include', 'JavaScript is a backend language !!'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824d367417b2b2512c52",
"title": "Test if a Value is a String",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#isString asserts that the actual value is a string."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[0].method, 'isNotString', 'A float number is not a string'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[1].method, 'isString', 'environment vars are strings (or undefined)'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - isString vs. isNotString",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=12').then(data => { assert.equal(data.assertions[2].method, 'isString', 'A JSON is a string'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824d367417b2b2512c53",
"title": "Test if a String Contains a Substring",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#include (on #notInclude ) works for strings too !!",
"It asserts that the actual string contains the expected substring"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.assertions[0].method, 'include', '\\'Arrow\\' contains \\'row\\'...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - include vs. notInclude",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=13').then(data => { assert.equal(data.assertions[1].method, 'notInclude', '... a \\'dart\\' doesn\\'t contain a \\'queue\\''); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824d367417b2b2512c54",
"title": "Use Regular Expressions to Test a String",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#match Asserts that the actual value",
"matches the second argument regular expression."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - match vs. notMatch",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.assertions[0].method, 'match', '\\'# name: John Doe, age: 35\\' matches the regex'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - match vs. notMatch",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=14').then(data => { assert.equal(data.assertions[1].method, 'notMatch', '\\'# name: Paul Smith III, age: twenty-four\\' does not match the regex (the age must be numeric)'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824e367417b2b2512c55",
"title": "Test if an Object has a Property",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#property asserts that the actual object has a given property.",
"Use #property or #notProperty where appropriate"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[0].method, 'notProperty', 'A car has not wings'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[1].method, 'property', 'planes have engines'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - property vs. notProperty",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=15').then(data => { assert.equal(data.assertions[2].method, 'property', 'Cars have wheels'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824e367417b2b2512c56",
"title": "Test if a Value is of a Specific Data Structure Type",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#typeOf asserts that values type is the given string, as determined by Object.prototype.toString.",
"Use #typeOf or #notTypeOf where appropriate"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[0].method, 'typeOf', 'myCar is typeOf Object'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[1].method, 'typeOf', 'Car.model is a String'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[2].method, 'notTypeOf', 'Plane.wings is a Number (not a String)'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[3].method, 'typeOf', 'Plane.engines is an Array'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - typeOf vs. notTypeOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=16').then(data => { assert.equal(data.assertions[4].method, 'typeOf', 'Car.wheels is a Number'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824e367417b2b2512c57",
"title": "Test if an Object is an Instance of a Constructor",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"#instanceOf asserts that an object is an instance of a constructor.",
"Use #instanceOf or #notInstanceOf where appropriate"
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[0].method, 'notInstanceOf', 'myCar is not an instance of Plane'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[1].method, 'instanceOf', 'airlinePlane is an instance of Plane'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[2].method, 'instanceOf', 'everything is an Object in JavaScript...'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "Choose the right assertion - instanceOf vs. notInstanceOf",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=unit&n=17').then(data => { assert.equal(data.assertions[3].method, 'notInstanceOf', 'myCar.wheels is not an instance of String'); }, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824e367417b2b2512c58",
"title": "Run Functional Tests on API Endpoints using Chai-HTTP",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Replace assert.fail(). Test the status and the text.response. Make the test pass.",
"Don't send a name in the query, the endpoint with responds with 'hello Guest'."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' == 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.text' == 'hello Guest'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=0').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.text'); assert.equal(data.assertions[1].args[1], '\\'hello Guest\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824f367417b2b2512c59",
"title": "Run Functional Tests on API Endpoints using Chai-HTTP II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"Replace assert.fail(). Test the status and the text.response. Make the test pass.",
"Send you name in the query appending ?name=<your_name>, the endpoint with responds with 'hello <your_name>'."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' == 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.text' == 'hello Guest'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=1').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.text'); assert.match(data.assertions[1].args[1], /hello [\\w\\d_-]/);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824f367417b2b2512c5a",
"title": "Run Functional Tests on an API Response using Chai-HTTP III - PUT method",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"In the next example we'll see how to send data in a request payload (body).",
"We are going to test a PUT request. The '/travellers' endpoint accepts",
"a JSON object taking the structure :",
" {surname: [last name of a traveller of the past]} ,",
"The route responds with :",
" {name: [first name], surname:[last name], dates: [birth - death years]}",
"see the server code for more details.",
"Send {surname: 'Colombo'}. Replace assert.fail() and make the test pass.",
"Check for 1) status, 2) type, 3) body.name, 4) body.surname",
"Follow the assertion order above, We rely on it."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' to be 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.type' to be 'application/json'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.type'); assert.equal(data.assertions[1].args[1], '\\'application/json\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.name' to be 'Cristoforo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[2].method, 'equal'); assert.equal(data.assertions[2].args[0], 'res.body.name'); assert.equal(data.assertions[2].args[1], '\\'Cristoforo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.surname' to be 'Colombo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=2').then(data => { assert.equal(data.assertions[3].method, 'equal'); assert.equal(data.assertions[3].args[0], 'res.body.surname'); assert.equal(data.assertions[3].args[1], '\\'Colombo\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824f367417b2b2512c5b",
"title": "Run Functional Tests on an API Response using Chai-HTTP IV - PUT method",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"This exercise is similar to the preceding. Look at it for the details.",
"Send {surname: 'da Verrazzano'}. Replace assert.fail() and make the test pass.",
"Check for 1) status, 2) type, 3) body.name, 4) body.surname",
"Follow the assertion order above, We rely on it."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.status' to be 200",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[0].method, 'equal'); assert.equal(data.assertions[0].args[0], 'res.status'); assert.equal(data.assertions[0].args[1], '200');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.type' to be 'application/json'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[1].method, 'equal'); assert.equal(data.assertions[1].args[0], 'res.type'); assert.equal(data.assertions[1].args[1], '\\'application/json\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.name' to be 'Giovanni'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[2].method, 'equal'); assert.equal(data.assertions[2].args[0], 'res.body.name'); assert.equal(data.assertions[2].args[1], '\\'Giovanni\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "You should test for 'res.body.surname' to be 'da Verrazzano'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=3').then(data => { assert.equal(data.assertions[3].method, 'equal'); assert.equal(data.assertions[3].args[0], 'res.body.surname'); assert.equal(data.assertions[3].args[1], '\\'da Verrazzano\\'');}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d824f367417b2b2512c5c",
"title": "Run Functional Tests using a Headless Browser",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"In the next challenges we are going to simulate the human interaction with a page using a device called 'Headless Browser'.",
"A headless browser is a web browser without a graphical user interface. These kind of tools are particularly useful for testing web pages as they are able to render and understand HTML, CSS, and JavaScript the same way a browser would.",
"For these challenges we are using Zombie.JS. It's a lightweight browser which is totally based on JS, without relying on additional binaries to be installed. This feature makes it usable in an environment such as Glitch. There are many other (more powerful) options.<br>",
"Look at the examples in the code for the exercise directions Follow the assertions order, We rely on it."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the headless browser request succeeded",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[0].method, 'browser.success'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#name' is 'Cristoforo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[1].method, 'browser.text'); assert.equal(data.assertions[1].args[0], '\\'span#name\\''); assert.equal(data.assertions[1].args[1], '\\'Cristoforo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#surname' is 'Colombo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[2].method, 'browser.text'); assert.equal(data.assertions[2].args[0], '\\'span#surname\\''); assert.equal(data.assertions[2].args[1], '\\'Colombo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the element 'span#dates' exist and its count is 1",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=4').then(data => { assert.equal(data.assertions[3].method, 'browser.element'); assert.equal(data.assertions[3].args[0], '\\'span#dates\\''); assert.equal(data.assertions[3].args[1], 1);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
},
{
"id": "587d8250367417b2b2512c5d",
"title": "Run Functional Tests using a Headless Browser II",
"description": [
"As a reminder, this project is being built upon the following starter project on <a href='https://glitch.com/#!/import/github/freeCodeCamp/boilerplate-mochachai/'>Glitch</a>, or cloned from <a href='https://github.com/freeCodeCamp/boilerplate-mochachai/'>GitHub</a>.",
"This exercise is similar to the preceding.",
"Look at the code for directions. Follow the assertions order, We rely on it."
],
"tests": [
{
"text": "All tests should pass",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.state,'passed'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": " assert that the headless browser request succeeded",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[0].method, 'browser.success'); }, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#name' is 'Amerigo'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[1].method, 'browser.text'); assert.equal(data.assertions[1].args[0], '\\'span#name\\''); assert.equal(data.assertions[1].args[1], '\\'Amerigo\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the text inside the element 'span#surname' is 'Vespucci'",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[2].method, 'browser.text'); assert.equal(data.assertions[2].args[0], '\\'span#surname\\''); assert.equal(data.assertions[2].args[1], '\\'Vespucci\\'');}, xhr => { throw new Error(xhr.responseText); })"
},
{
"text": "assert that the element 'span#dates' exist and its count is 1",
"testString": "getUserInput => $.get(getUserInput('url') + '/_api/get-tests?type=functional&n=5').then(data => { assert.equal(data.assertions[3].method, 'browser.element'); assert.equal(data.assertions[3].args[0], '\\'span#dates\\''); assert.equal(data.assertions[3].args[1], 1);}, xhr => { throw new Error(xhr.responseText); })"
}
],
"solutions": [],
"hints": [],
"challengeType": 2,
"releasedOn": "Feb 17, 2017",
"translations": {}
}
]
}

View File

@ -0,0 +1,702 @@
{
"name": "Algorithms",
"order": 1,
"time": "",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "a3f503de51cf954ede28891d",
"title": "Find the Symmetric Difference",
"description": [
"Create a function that takes two or more arrays and returns an array of the <dfn>symmetric difference</dfn> (<code>&xutri;</code> or <code>&oplus;</code>) of the provided arrays.",
"Given two sets (for example set <code>A = {1, 2, 3}</code> and set <code>B = {2, 3, 4}</code>), the mathematical term \"symmetric difference\" of two sets is the set of elements which are in either of the two sets, but not in both (<code>A &xutri; B = C = {1, 4}</code>). For every additional symmetric difference you take (say on a set <code>D = {2, 3}</code>), you should get the set with elements which are in either of the two the sets but not both (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>). The resulting array must contain only unique values (<em>no duplicates</em>).",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"function sym() {\n var arrays = [].slice.call(arguments);\n return arrays.reduce(function (symDiff, arr) {\n return symDiff.concat(arr).filter(function (val, idx, theArr) {\n return theArr.indexOf(val) === idx \n && (symDiff.indexOf(val) === -1 || arr.indexOf(val) === -1);\n });\n });\n}\nsym([1, 2, 3], [5, 2, 1, 4]);\n"
],
"tests": [
{
"text": "<code>sym([1, 2, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.",
"testString": "assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4]), [3, 4, 5], '<code>sym([1, 2, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.');"
},
{
"text": "<code>sym([1, 2, 3], [5, 2, 1, 4])</code> should contain only three elements.",
"testString": "assert.equal(sym([1, 2, 3], [5, 2, 1, 4]).length, 3, '<code>sym([1, 2, 3], [5, 2, 1, 4])</code> should contain only three elements.');"
},
{
"text": "<code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.",
"testString": "assert.sameMembers(sym([1, 2, 3, 3], [5, 2, 1, 4]), [3, 4, 5], '<code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should return <code>[3, 4, 5]</code>.');"
},
{
"text": "<code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should contain only three elements.",
"testString": "assert.equal(sym([1, 2, 3, 3], [5, 2, 1, 4]).length, 3, '<code>sym([1, 2, 3, 3], [5, 2, 1, 4])</code> should contain only three elements.');"
},
{
"text": "<code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should return <code>[3, 4, 5]</code>.",
"testString": "assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4, 5]), [3, 4, 5], '<code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should return <code>[3, 4, 5]</code>.');"
},
{
"text": "<code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should contain only three elements.",
"testString": "assert.equal(sym([1, 2, 3], [5, 2, 1, 4, 5]).length, 3, '<code>sym([1, 2, 3], [5, 2, 1, 4, 5])</code> should contain only three elements.');"
},
{
"text": "<code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should return <code>[1, 4, 5]</code>",
"testString": "assert.sameMembers(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], '<code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should return <code>[1, 4, 5]</code>');"
},
{
"text": "<code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should contain only three elements.",
"testString": "assert.equal(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]).length, 3, '<code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should contain only three elements.');"
},
{
"text": "<code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.",
"testString": "assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], '<code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.');"
},
{
"text": "<code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should contain only three elements.",
"testString": "assert.equal(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]).length, 3, '<code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should contain only three elements.');"
},
{
"text": "<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should return <code>[2, 3, 4, 6, 7]</code>.",
"testString": "assert.sameMembers(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]), [2, 3, 4, 6, 7], '<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should return <code>[2, 3, 4, 6, 7]</code>.');"
},
{
"text": "<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should contain only five elements.",
"testString": "assert.equal(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3]).length, 5, '<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3])</code> should contain only five elements.');"
},
{
"text": "<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should return <code>[1, 2, 4, 5, 6, 7, 8, 9]</code>.",
"testString": "assert.sameMembers(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1]), [1, 2, 4, 5, 6, 7, 8, 9], '<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should return <code>[1, 2, 4, 5, 6, 7, 8, 9]</code>.');"
},
{
"text": "<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should contain only eight elements.",
"testString": "assert.equal(sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1]).length, 8, '<code>sym([3, 3, 3, 2, 5], [2, 1, 5, 7], [3, 4, 6, 6], [1, 2, 3], [5, 3, 9, 8], [1])</code> should contain only eight elements.');"
}
],
"MDNlinks": [
"Array.prototype.reduce()",
"Symmetric Difference"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Diferencia Simétrica",
"description": [
"Crea una función que acepte dos o más arreglos y que devuelva un arreglo conteniendo la diferenia simétrica entre ambos",
"En Matemáticas, el término 'diferencia simétrica' se refiere a los elementos en dos conjuntos que están en el primer conjunto o en el segundo, pero no en ambos.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Differenza Simmetrica",
"description": [
"Crea una funzione che accetti due o più array e che ritorni un array contenente la <dfn>differenza simmetrica</dfn> (<code>&xutri;</code> o <code>&oplus;</code>) degli stessi.",
"Dati due insiemi (per esempio l'insieme <code>A = {1, 2, 3}<code> e l'insieme <code>B = {2, 3, 4}</code>, il termine matematico \"differenza simmetrica\" di due insiemi è l'insieme degli elementi che sono in almeno uno dei due insiemi, ma non in entrambi (<code>A &xutri; B = C = {1, 4}</code>). Per ogni differenza simmetrica aggiuntiva che fai (per esempio su un insieme <code>D = {2, 3}</code>), devi prendere l'insieme degli elementi che sono in almeno uno dei due insiemi ma non in entrambi (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>).",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Diferença Simétrica",
"description": [
"Crie uma função que recebe duas ou mais matrizes e retorna a matriz <dfn>diferença simétrica</dfn> (<code>&xutri;</code> ou <code>&oplus;</code>) das matrizes fornecidas.",
"Dado dois conjuntos (por exemplo conjunto <code>A = {1, 2, 3}</code> e conjunto <code>B = {2, 3, 4}</code>), o termo matemático \"diferença simétrica\" dos dois cojuntos é o conjunto dos elementos que estão em um dos conjuntos, mas não nos dois (<code>A &xutri; B = C = {1, 4}</code>). Para cada diferença simétrica adicional que você faz (digamos em um terceiro conjunto <code>D = {2, 3}</code>), voce deve retornar o conjunto no qual os elementos estão em um dos conjuntos mas não nos dois (<code>C &xutri; D = {1, 4} &xutri; {2, 3} = {1, 2, 3, 4}</code>). O conjunto final deve ter somentes valores únicos (<em>sem números repetidos</em>).",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function sym(args) {",
" return args;",
"}",
"",
"sym([1, 2, 3], [5, 2, 1, 4]);"
],
"head": [],
"tail": []
}
}
},
{
"id": "a56138aff60341a09ed6c480",
"title": "Inventory Update",
"description": [
"Compare and update the inventory stored in a 2D array against a second 2D array of a fresh delivery. Update the current existing inventory item quantities (in <code>arr1</code>). If an item cannot be found, add the new item and quantity into the inventory array. The returned inventory array should be in alphabetical order by item.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"function updateInventory(arr1, arr2) {\n arr2.forEach(function(item) {\n createOrUpdate(arr1, item);\n });\n // All inventory must be accounted for or you're fired!\n return arr1;\n}\n\nfunction createOrUpdate(arr1, item) {\n var index = -1;\n while (++index < arr1.length) {\n if (arr1[index][1] === item[1]) {\n arr1[index][0] += item[0];\n return;\n }\n if (arr1[index][1] > item[1]) {\n break;\n }\n }\n arr1.splice(index, 0, item);\n}\n\n// Example inventory lists\nvar curInv = [\n [21, 'Bowling Ball'],\n [2, 'Dirty Sock'],\n [1, 'Hair Pin'],\n [5, 'Microphone']\n];\n\nvar newInv = [\n [2, 'Hair Pin'],\n [3, 'Half-Eaten Apple'],\n [67, 'Bowling Ball'],\n [7, 'Toothpaste']\n];\n\nupdateInventory(curInv, newInv);\n"
],
"tests": [
{
"text": "The function <code>updateInventory</code> should return an array.",
"testString": "assert.isArray(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), 'The function <code>updateInventory</code> should return an array.');"
},
{
"text": "<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return an array with a length of 6.",
"testString": "assert.equal(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]).length, 6, '<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return an array with a length of 6.');"
},
{
"text": "<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[88, \"Bowling Ball\"], [2, \"Dirty Sock\"], [3, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [5, \"Microphone\"], [7, \"Toothpaste\"]]</code>.",
"testString": "assert.deepEqual(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), [[88, \"Bowling Ball\"], [2, \"Dirty Sock\"], [3, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [5, \"Microphone\"], [7, \"Toothpaste\"]], '<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[88, \"Bowling Ball\"], [2, \"Dirty Sock\"], [3, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [5, \"Microphone\"], [7, \"Toothpaste\"]]</code>.');"
},
{
"text": "<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [])</code> should return <code>[[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]]</code>.",
"testString": "assert.deepEqual(updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], []), [[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], '<code>updateInventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [])</code> should return <code>[[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]]</code>.');"
},
{
"text": "<code>updateInventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]]</code>.",
"testString": "assert.deepEqual(updateInventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), [[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]], '<code>updateInventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]])</code> should return <code>[[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]]</code>.');"
},
{
"text": "<code>updateInventory([[0, \"Bowling Ball\"], [0, \"Dirty Sock\"], [0, \"Hair Pin\"], [0, \"Microphone\"]], [[1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [1, \"Bowling Ball\"], [1, \"Toothpaste\"]])</code> should return <code>[[1, \"Bowling Ball\"], [0, \"Dirty Sock\"], [1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [0, \"Microphone\"], [1, \"Toothpaste\"]]</code>.",
"testString": "assert.deepEqual(updateInventory([[0, \"Bowling Ball\"], [0, \"Dirty Sock\"], [0, \"Hair Pin\"], [0, \"Microphone\"]], [[1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [1, \"Bowling Ball\"], [1, \"Toothpaste\"]]), [[1, \"Bowling Ball\"], [0, \"Dirty Sock\"], [1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [0, \"Microphone\"], [1, \"Toothpaste\"]], '<code>updateInventory([[0, \"Bowling Ball\"], [0, \"Dirty Sock\"], [0, \"Hair Pin\"], [0, \"Microphone\"]], [[1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [1, \"Bowling Ball\"], [1, \"Toothpaste\"]])</code> should return <code>[[1, \"Bowling Ball\"], [0, \"Dirty Sock\"], [1, \"Hair Pin\"], [1, \"Half-Eaten Apple\"], [0, \"Microphone\"], [1, \"Toothpaste\"]]</code>.');"
}
],
"MDNlinks": [
"Global Array Object"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Actualizando el Inventario",
"description": [
"Compara y actualiza el inventario actual, almacenado en un arreglo bidimensional, contra otro arreglo bidimensional de inventario nuevo. Actualiza las cantidades en el inventario actual y, en caso de recibir una nueva mercancía, añade su nombre y la cantidad recibida al arreglo del inventario en orden alfabético.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Aggiornamento dell'Inventario",
"description": [
"Confronta e aggiorna l'inventario, contenuto in un array bidimensionale, con un secondo array bidimensionale relativo ad una nuova consegna. Aggiorna le quantità disponibili in inventario (dentro <code>arr1</code>). Se uno degli articoli non è presente nell'inventario, aggiungi allo stesso il nuovo articolo e la sua quantità. Ritorna un array con l'inventario aggiornato, che deve essere ordinato alfabeticamente per articolo.",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Atualizando Inventário",
"description": [
"Compare e atualize o inventário armazenado em um matriz 2D contra uma segunda matriz 2D de uma entrega recente. Atualize a quantidade de itens no inventário atual (em <code>arr1</code>). Se um item não pode ser encontrado, adicione um novo item e a sua quantidade na matriz do inventário. O inventário retornado deve estar em ordem alfabética por item.",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function updateInventory(arr1, arr2) {",
" // All inventory must be accounted for or you're fired!",
" return arr1;",
"}",
"",
"// Example inventory lists",
"var curInv = [",
" [21, \"Bowling Ball\"],",
" [2, \"Dirty Sock\"],",
" [1, \"Hair Pin\"],",
" [5, \"Microphone\"]",
"];",
"",
"var newInv = [",
" [2, \"Hair Pin\"],",
" [3, \"Half-Eaten Apple\"],",
" [67, \"Bowling Ball\"],",
" [7, \"Toothpaste\"]",
"];",
"",
"updateInventory(curInv, newInv);"
],
"head": [],
"tail": []
}
}
},
{
"id": "a7bf700cd123b9a54eef01d5",
"title": "No Repeats Please",
"description": [
"Return the number of total permutations of the provided string that don't have repeated consecutive letters. Assume that all characters in the provided string are each unique.",
"For example, <code>aab</code> should return 2 because it has 6 total permutations (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), but only 2 of them (<code>aba</code> and <code>aba</code>) don't have the same letter (in this case <code>a</code>) repeating.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"function permAlone(str) {\n return permutor(str).filter(function(perm) {\n return !perm.match(/(.)\\1/g);\n }).length;\n}\n\nfunction permutor(str) {\n // http://staff.roguecc.edu/JMiller/JavaScript/permute.html\n //permArr: Global array which holds the list of permutations\n //usedChars: Global utility array which holds a list of \"currently-in-use\" characters\n var permArr = [], usedChars = [];\n function permute(input) {\n //convert input into a char array (one element for each character)\n var i, ch, chars = input.split(\"\");\n for (i = 0; i < chars.length; i++) {\n //get and remove character at index \"i\" from char array\n ch = chars.splice(i, 1);\n //add removed character to the end of used characters\n usedChars.push(ch);\n //when there are no more characters left in char array to add, add used chars to list of permutations\n if (chars.length === 0) permArr[permArr.length] = usedChars.join(\"\");\n //send characters (minus the removed one from above) from char array to be permuted\n permute(chars.join(\"\"));\n //add removed character back into char array in original position\n chars.splice(i, 0, ch);\n //remove the last character used off the end of used characters array\n usedChars.pop();\n }\n }\n permute(str);\n return permArr;\n}\n\npermAlone('aab');\n"
],
"tests": [
{
"text": "<code>permAlone(\"aab\")</code> should return a number.",
"testString": "assert.isNumber(permAlone('aab'), '<code>permAlone(\"aab\")</code> should return a number.');"
},
{
"text": "<code>permAlone(\"aab\")</code> should return 2.",
"testString": "assert.strictEqual(permAlone('aab'), 2, '<code>permAlone(\"aab\")</code> should return 2.');"
},
{
"text": "<code>permAlone(\"aaa\")</code> should return 0.",
"testString": "assert.strictEqual(permAlone('aaa'), 0, '<code>permAlone(\"aaa\")</code> should return 0.');"
},
{
"text": "<code>permAlone(\"aabb\")</code> should return 8.",
"testString": "assert.strictEqual(permAlone('aabb'), 8, '<code>permAlone(\"aabb\")</code> should return 8.');"
},
{
"text": "<code>permAlone(\"abcdefa\")</code> should return 3600.",
"testString": "assert.strictEqual(permAlone('abcdefa'), 3600, '<code>permAlone(\"abcdefa\")</code> should return 3600.');"
},
{
"text": "<code>permAlone(\"abfdefa\")</code> should return 2640.",
"testString": "assert.strictEqual(permAlone('abfdefa'), 2640, '<code>permAlone(\"abfdefa\")</code> should return 2640.');"
},
{
"text": "<code>permAlone(\"zzzzzzzz\")</code> should return 0.",
"testString": "assert.strictEqual(permAlone('zzzzzzzz'), 0, '<code>permAlone(\"zzzzzzzz\")</code> should return 0.');"
},
{
"text": "<code>permAlone(\"a\")</code> should return 1.",
"testString": "assert.strictEqual(permAlone('a'), 1, '<code>permAlone(\"a\")</code> should return 1.');"
},
{
"text": "<code>permAlone(\"aaab\")</code> should return 0.",
"testString": "assert.strictEqual(permAlone('aaab'), 0, '<code>permAlone(\"aaab\")</code> should return 0.');"
},
{
"text": "<code>permAlone(\"aaabb\")</code> should return 12.",
"testString": "assert.strictEqual(permAlone('aaabb'), 12, '<code>permAlone(\"aaabb\")</code> should return 12.');"
}
],
"MDNlinks": [
"Permutations",
"RegExp"
],
"challengeType": 5,
"translations": {
"es": {
"title": "Sin Repeticiones, por Favor",
"description": [
"Crea una función que devuelva el número total de permutaciones de las letras en la cadena de texto provista, en las cuales no haya letras consecutivas repetidas",
"Por ejemplo, 'aab' debe retornar 2 porque, del total de 6 permutaciones posibles, solo 2 de ellas no tienen repetida la misma letra (en este caso 'a').",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "Niente Ripetizioni, per Favore",
"description": [
"Ritorna il numero totale di permutazioni della stringa passata che non hanno lettere consecutive riptetute. Assumi che tutti i caratteri nella stringa passata siano unici.",
"Per esempio, <code>aab</code> deve ritornare 2, perchè la stringa ha 6 permutazioni possibili in totale (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), ma solo 2 di loro (<code>aba</code> e <code>aba</code>) non contengono la stessa lettera (in questo caso <code>a</code> ripetuta).",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Sem repetição, por favor",
"description": [
"Retorne o número total de permutações da string fornecida que não tem letras consecutivas repetidas. Assuma que todos os caracteres na string fornecida são únicos.",
"Por exemplo, <code>aab</code> deve retornar 2 porque tem um total de 6 permutações (<code>aab</code>, <code>aab</code>, <code>aba</code>, <code>aba</code>, <code>baa</code>, <code>baa</code>), mas somente duas delas (<code>aba</code> and <code>aba</code>) não tem a mesma letra (nesse caso <code>a</code>) se repetindo.",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function permAlone(str) {",
" return str;",
"}",
"",
"permAlone('aab');"
],
"head": [],
"tail": []
}
}
},
{
"id": "a3f503de51cfab748ff001aa",
"title": "Pairwise",
"description": [
"Given an array <code>arr</code>, find element pairs whose sum equal the second argument <code>arg</code> and return the sum of their indices.",
"You may use multiple pairs that have the same numeric elements but different indices. Each pair should use the lowest possible available indices. Once an element has been used it cannot be reused to pair with another element. For instance, <code>pairwise([1, 1, 2], 3)</code> creates a pair <code>[2, 1]</code> using the 1 at indice 0 rather than the 1 at indice 1, because 0+2 < 1+2.",
"For example <code>pairwise([7, 9, 11, 13, 15], 20)</code> returns <code>6</code>. The pairs that sum to 20 are <code>[7, 13]</code> and <code>[9, 11]</code>. We can then write out the array with their indices and values.",
"<table class=\"table\"><tr><th><strong>Index</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Value</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Below we'll take their corresponding indices and add them.",
"7 + 13 = 20 &#8594; Indices 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indices 1 + 2 = 3<br>3 + 3 = 6 &#8594 Return <code>6</code>",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"solutions": [
"function pairwise(arr, arg) {\n var sum = 0;\n arr.forEach(function(e, i, a) {\n if (e != null) { \n var diff = arg-e;\n a[i] = null;\n var dix = a.indexOf(diff);\n if (dix !== -1) {\n sum += dix;\n sum += i;\n a[dix] = null;\n } \n }\n });\n return sum;\n}\n\npairwise([1,4,2,3,0,5], 7);\n"
],
"tests": [
{
"text": "<code>pairwise([1, 4, 2, 3, 0, 5], 7)</code> should return 11.",
"testString": "assert.deepEqual(pairwise([1, 4, 2, 3, 0, 5], 7), 11, '<code>pairwise([1, 4, 2, 3, 0, 5], 7)</code> should return 11.');"
},
{
"text": "<code>pairwise([1, 3, 2, 4], 4)</code> should return 1.",
"testString": "assert.deepEqual(pairwise([1, 3, 2, 4], 4), 1, '<code>pairwise([1, 3, 2, 4], 4)</code> should return 1.');"
},
{
"text": "<code>pairwise([1, 1, 1], 2)</code> should return 1.",
"testString": "assert.deepEqual(pairwise([1, 1, 1], 2), 1, '<code>pairwise([1, 1, 1], 2)</code> should return 1.');"
},
{
"text": "<code>pairwise([0, 0, 0, 0, 1, 1], 1)</code> should return 10.",
"testString": "assert.deepEqual(pairwise([0, 0, 0, 0, 1, 1], 1), 10, '<code>pairwise([0, 0, 0, 0, 1, 1], 1)</code> should return 10.');"
},
{
"text": "<code>pairwise([], 100)</code> should return 0.",
"testString": "assert.deepEqual(pairwise([], 100), 0, '<code>pairwise([], 100)</code> should return 0.');"
}
],
"MDNlinks": [
"Array.prototype.reduce()"
],
"challengeType": 5,
"translations": {
"es": {
"title": "En Parejas",
"description": [
"Crea una función que devuelva la suma de todos los índices de los elementos de 'arr' que pueden ser emparejados con otro elemento de tal forma que la suma de ambos equivalga al valor del segundo argumento, 'arg'. Si varias combinaciones son posibles, devuelve la menor suma de índices. Una vez un elemento ha sido usado, no puede ser usado de nuevo para emparejarlo con otro elemento.",
"Por ejemplo, pairwise([1, 4, 2, 3, 0, 5], 7) debe devolver 11 porque 4, 2, 3 y 5 pueden ser emparejados para obtener una suma de 7",
"pairwise([1, 3, 2, 4], 4) devolvería el valor de 1, porque solo los primeros dos elementos pueden ser emparejados para sumar 4. ¡Recuerda que el primer elemento tiene un índice de 0!",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado. Intenta programar en pareja. Escribe tu propio código."
]
},
"it": {
"title": "A Coppie",
"description": [
"Dato un array <code>arr</code>, trova le coppie di elementi la cui somma è uguale al secondo argomento passato <code>arg</code>. Ritorna quindi la somma dei loro indici.",
"Se ci sono più coppie possibili che hanno lo stesso valore numerico ma indici differenti, ritorna la somma degli indici minore. Una volta usato un elemento, lo stesso non può essere riutilizzato per essere accoppiato con un altro.",
"Per esempio <code>pairwise([7, 9, 11, 13, 15], 20)</code> ritorna <code>6</code>. Le coppia la cui somma è 20 sono <code>[7, 13]</code> e <code>[9, 11]</code>. Possiamo quindi osservare l'array con i loro indici e valori.",
"<table class=\"table\"><tr><th><strong>Indice</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Valore</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Qui sotto prendiamo gli indici corrispondenti e li sommiamo.",
"7 + 13 = 20 &#8594; Indici 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indici 1 + 2 = 3<br>3 + 3 = 6 &#8594 Ritorna <code>6</code>",
"Ricorda di usare <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leggi-Cerca-Chiedi</a> se rimani bloccato. Prova a programmare in coppia. Scrivi il codice da te."
]
},
"pt-br": {
"title": "Emparelhados",
"description": [
"Dado uma matriz <code>arr</code>, encontre pares de elementos no qual a soma é igual ao segundo argumento <code>arg</code> e retorne a soma dos seus indices.",
"Se multiplos pares tem o mesmo elemento numérico mas indices diferentes, retorne a soma dos menores indices. Uma vez que um elemento é usado, este não pode ser emparelhado novamente com outro elemento.",
"Por exemplo <code>pairwise([7, 9, 11, 13, 15], 20)</code> retorna <code>6</code>. Os pares que somam 20 são <code>[7, 13]</code> e <code>[9, 11]</code>. Nós podemos então criar a matriz com seus indices e valores.",
"<table class=\"table\"><tr><th><strong>Index</strong></th><th>0</th><th>1</th><th>2</th><th>3</th><th>4</th></tr><tr><td>Value</td><td>7</td><td>9</td><td>11</td><td>13</td><td>15</td></tr></table>",
"Abaixo nós pegamos os índices correspondentes e somá-los.",
"7 + 13 = 20 &#8594; Indices 0 + 3 = 3<br>9 + 11 = 20 &#8594; Indices 1 + 2 = 3<br>3 + 3 = 6 &#8594 Retorna <code>6</code>",
"Lembre-se de usar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Ler-Procurar-Perguntar</a> se você ficar preso. Tente programar em par. Escreva seu próprio código."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function pairwise(arr, arg) {",
" return arg;",
"}",
"",
"pairwise([1,4,2,3,0,5], 7);"
],
"head": [],
"tail": []
}
}
},
{
"id": "8d5123c8c441eddfaeb5bdef",
"title": "Implement Bubble Sort",
"description": [
"This is the first of several challenges on sorting algorithms. Given an array of unsorted items, we want to be able to return a sorted array. We will see several different methods to do this and learn some tradeoffs between these different approaches. While most modern languages have built-in sorting methods for operations like this, it is still important to understand some of the common basic approaches and learn how they can be implemented.",
"Here we will see bubble sort. The bubble sort method starts at the beginning of an unsorted array and 'bubbles up' unsorted values towards the end, iterating through the array until it is completely sorted. It does this by comparing adjacent items and swapping them if they are out of order. The method continues looping through the array until no swaps occur at which point the array is sorted.",
"This method requires multiple iterations through the array and for average and worst cases has quadratic time complexity. While simple, it is usually impractical in most situations.",
"<strong>Instructions:</strong> Write a function <code>bubbleSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting algorithm in action!"
],
"tests": [
{
"text": "<code>bubbleSort</code> is a function.",
"testString": "assert(typeof bubbleSort == 'function', '<code>bubbleSort</code> is a function.');"
},
{
"text": "<code>bubbleSort</code> returns a sorted array (least to greatest).",
"testString": "assert(isSorted(bubbleSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), '<code>bubbleSort</code> returns a sorted array (least to greatest).');"
},
{
"text": "<code>bubbleSort</code> returns an array that is unchanged except for order.",
"testString": "assert.sameMembers(bubbleSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], '<code>bubbleSort</code> returns an array that is unchanged except for order.');"
},
{
"text": "<code>bubbleSort</code> should not use the built-in <code>.sort()</code> method.",
"testString": "assert.strictEqual(code.search(/\\.sort\\(/), -1, '<code>bubbleSort</code> should not use the built-in <code>.sort()</code> method.');"
}
],
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017",
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function bubbleSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"head": [],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
]
}
}
},
{
"id": "587d8259367417b2b2512c85",
"title": "Implement Selection Sort",
"description": [
"Here we will implement selection sort. Selection sort works by selecting the minimum value in a list and swapping it with the first value in the list. It then starts at the second position, selects the smallest value in the remaining list, and swaps it with the second element. It continues iterating through the list and swapping elements until it reaches the end of the list. Now the list is sorted. Selection sort has quadratic time complexity in all cases.",
"<strong>Instructions</strong>: Write a function <code>selectionSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting algorithm in action!"
],
"tests": [
{
"text": "<code>selectionSort</code> is a function.",
"testString": "assert(typeof selectionSort == 'function', '<code>selectionSort</code> is a function.');"
},
{
"text": "<code>selectionSort</code> returns a sorted array (least to greatest).",
"testString": "assert(isSorted(selectionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), '<code>selectionSort</code> returns a sorted array (least to greatest).');"
},
{
"text": "<code>selectionSort</code> returns an array that is unchanged except for order.",
"testString": "assert.sameMembers(selectionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], '<code>selectionSort</code> returns an array that is unchanged except for order.');"
},
{
"text": "<code>selectionSort</code> should not use the built-in <code>.sort()</code> method.",
"testString": "assert.strictEqual(code.search(/\\.sort\\(/), -1, '<code>selectionSort</code> should not use the built-in <code>.sort()</code> method.');"
}
],
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017",
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function selectionSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"head": [],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
]
}
}
},
{
"id": "587d8259367417b2b2512c86",
"title": "Implement Insertion Sort",
"description": [
"The next sorting method we'll look at is insertion sort. This method works by building up a sorted array at the beginning of the list. It begins the sorted array with the first element. Then it inspects the next element and swaps it backwards into the sorted array until it is in sorted position. It continues iterating through the list and swapping new items backwards into the sorted portion until it reaches the end. This algorithm has quadratic time complexity in the average and worst cases.",
"<strong>Instructions:</strong> Write a function <code>insertionSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting algorithm in action!"
],
"tests": [
{
"text": "<code>insertionSort</code> is a function.",
"testString": "assert(typeof insertionSort == 'function', '<code>insertionSort</code> is a function.');"
},
{
"text": "<code>insertionSort</code> returns a sorted array (least to greatest).",
"testString": "assert(isSorted(insertionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), '<code>insertionSort</code> returns a sorted array (least to greatest).');"
},
{
"text": "<code>insertionSort</code> returns an array that is unchanged except for order.",
"testString": "assert.sameMembers(insertionSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], '<code>insertionSort</code> returns an array that is unchanged except for order.');"
},
{
"text": "<code>insertionSort</code> should not use the built-in <code>.sort()</code> method.",
"testString": "assert.strictEqual(code.search(/\\.sort\\(/), -1, '<code>insertionSort</code> should not use the built-in <code>.sort()</code> method.');"
}
],
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017",
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function insertionSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"head": [],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
]
}
}
},
{
"id": "587d825a367417b2b2512c89",
"title": "Implement Quick Sort",
"description": [
"Here we will move on to an intermediate sorting algorithm: quick sort. Quick sort is an efficient, recursive divide-and-conquer approach to sorting an array. In this method, a pivot value is chosen in the original array. The array is then partitioned into two subarrays of values less than and greater than the pivot value. We then combine the result of recursively calling the quick sort algorithm on both sub-arrays. This continues until the base case of an empty or single-item array is reached, which we return. The unwinding of the recursive calls return us the sorted array.",
"Quick sort is a very efficient sorting method, providing <i>O(nlog(n))</i> performance on average. It is also relatively easy to implement. These attributes make it a popular and useful sorting method.",
"<strong>Instructions:</strong> Write a function <code>quickSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest. While the choice of the pivot value is important, any pivot will do for our purposes here. For simplicity, the first or last element could be used.",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting algorithm in action!"
],
"tests": [
{
"text": "<code>quickSort</code> is a function.",
"testString": "assert(typeof quickSort == 'function', '<code>quickSort</code> is a function.');"
},
{
"text": "<code>quickSort</code> returns a sorted array (least to greatest).",
"testString": "assert(isSorted(quickSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), '<code>quickSort</code> returns a sorted array (least to greatest).');"
},
{
"text": "<code>quickSort</code> returns an array that is unchanged except for order.",
"testString": "assert.sameMembers(quickSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], '<code>quickSort</code> returns an array that is unchanged except for order.');"
},
{
"text": "<code>quickSort</code> should not use the built-in <code>.sort()</code> method.",
"testString": "assert.strictEqual(code.search(/\\.sort\\(/), -1, '<code>quickSort</code> should not use the built-in <code>.sort()</code> method.');"
}
],
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017",
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function quickSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"head": [],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
]
}
}
},
{
"id": "587d825c367417b2b2512c8f",
"title": "Implement Merge Sort",
"description": [
"Another intermediate sorting algorithm that is very common is merge sort. Like quick sort, merge sort also uses a divide-and-conquer, recursive methodology to sort an array. It takes advantage of the fact that it is relatively easy to sort two arrays as long as each is sorted in the first place. But we'll start with only one array as input, so how do we get to two sorted arrays from that? Well, we can recursively divide the original input in two until we reach the base case of an array with one item. A single-item array is naturally sorted, so then we can start combining. This combination will unwind the recursive calls that split the original array, eventually producing a final sorted array of all the elements. The steps of merge sort, then, are:",
"<strong>1)</strong> Recursively split the input array in half until a sub-array with only one element is produced.",
"<strong>2)</strong> Merge each sorted sub-array together to produce the final sorted array.",
"Merge sort is an efficient sorting method, with time complexity of <i>O(nlog(n))</i>. This algorithm is popular because it is performant and relatively easy to implement.",
"As an aside, this will be the last sorting algorithm we cover here. However, later in the section on tree data structures we will describe heap sort, another efficient sorting method that requires a binary heap in its implementation.",
"<strong>Instructions:</strong> Write a function <code>mergeSort</code> which takes an array of integers as input and returns an array of these integers in sorted order from least to greatest. A good way to implement this is to write one function, for instance <code>merge</code>, which is responsible for merging two sorted arrays, and another function, for instance <code>mergeSort</code>, which is responsible for the recursion that produces single-item arrays to feed into merge. Good luck!",
"<strong>Note:</strong><br>We are calling this function from behind the scenes; the test array we are using is commented out in the editor. Try logging <code>array</code> to see your sorting algorithm in action!"
],
"tests": [
{
"text": "<code>mergeSort</code> is a function.",
"testString": "assert(typeof mergeSort == 'function', '<code>mergeSort</code> is a function.');"
},
{
"text": "<code>mergeSort</code> returns a sorted array (least to greatest).",
"testString": "assert(isSorted(mergeSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92])), '<code>mergeSort</code> returns a sorted array (least to greatest).');"
},
{
"text": "<code>mergeSort</code> returns an array that is unchanged except for order.",
"testString": "assert.sameMembers(mergeSort([1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92]), [1,4,2,8,345,123,43,32,5643,63,123,43,2,55,1,234,92], '<code>mergeSort</code> returns an array that is unchanged except for order.');"
},
{
"text": "<code>mergeSort</code> should not use the built-in <code>.sort()</code> method.",
"testString": "assert.strictEqual(code.search(/\\.sort\\(/), -1, '<code>mergeSort</code> should not use the built-in <code>.sort()</code> method.');"
}
],
"solutions": [],
"challengeType": 1,
"translations": {},
"releasedOn": "February 17, 2017",
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"function mergeSort(array) {",
" // change code below this line",
"",
" // change code above this line",
" return array;",
"}",
"",
"// test array:",
"// [1, 4, 2, 8, 345, 123, 43, 32, 5643, 63, 123, 43, 2, 55, 1, 234, 92]"
],
"head": [],
"tail": [
"function isSorted(arr) {",
" var check = (i) => (i == arr.length - 1) ? true : (arr[i] > arr[i + 1]) ? false : check(i + 1);",
" return check(0);",
"};"
]
}
}
}
]
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,249 @@
# A guide to improve Project Euler's problems
Thank you for contributing to freeCodeCamp, your help is definitely needed here!
freeCodeCamp is having a great breakthrough ahead, one of it is to prepare
campers for interview questions, and Project Euler is one of them.
And to let campers having fun with this challenges during Christmas, we are
going to have a lot of help here to improve the challenges of Project Euler
problems (so people won't cheating by returning the value right away, since
Project Euler's problems only assert one answer.)
**Table of Contents**
* [What is Project Euler](#what-is-project-euler)
* [How to improve the problems](#how-to-improve-the-problems)
## What is Project Euler
[Project Euler](https://projecteuler.net/) is a series of challenging
mathematical/computer programming problems that will require more than just
mathematical insights to solve. Although mathematics will help you arrive at
elegant and efficient methods, the use of a computer and programming skills will
be required to solve most problems.
The motivation for starting Project Euler, and its continuation, is to provide a
platform for the inquiring mind to delve into unfamiliar areas and learn new
concepts in a fun and recreational context.
## How to improve the problems
The Project Euler problems seed can be found at
`seed/challenges/08-coding-interview-questions-and-take-home-assignments/project-euler-problems.json`
Here's what it will look like (this is before the improvements, take problem 23
as the example)
```javascript
{
"_id": "5900f3831000cf542c50fe96",
"challengeType": 5,
"type": "bonfire",
"title": "Problem 23: Non-abundant sums",
"tests": [
"assert.strictEqual(euler23(), 4179871, 'message: <code>euler23()</code> should return 4179871.');"
],
"solutions": [],
"translations": {},
"challengeSeed": [
"function euler23() {",
" // Good luck!",
" return true;",
"}",
"",
"euler23();"
],
"description": [
"A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.",
"A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.",
"",
"As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.",
"Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers."
]
},
```
and here's after some improvements
```javascript
{
"_id": "5900f3831000cf542c50fe96",
"challengeType": 5,
"type": "bonfire",
"title": "Problem 23: Non-abundant sums",
"tests": [
"assert(sumOfNonAbundantNumbers(10000) === 3731004, 'message: <code>sumOfNonAbundantNumbers(10000)</code> should return 3731004.');",
"assert(sumOfNonAbundantNumbers(15000) === 4039939, 'message: <code>sumOfNonAbundantNumbers(15000)</code> should return 4039939.');",
"assert(sumOfNonAbundantNumbers(20000) === 4159710, 'message: <code>sumOfNonAbundantNumbers(20000)</code> should return 4159710.');",
"assert(sumOfNonAbundantNumbers(28123) === 4179871, 'message: <code>sumOfNonAbundantNumbers(28123)</code> should return 4179871.');"
],
"solutions": [],
"translations": {},
"challengeSeed": [
"function sumOfNonAbundantNumbers(n) {",
" // Good luck!",
" return n;",
"}",
"",
"sumOfNonAbundantNumbers(28123);"
],
"description": [
"A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.",
"A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.",
"",
"As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.",
"Find the sum of all positive integers <= n which cannot be written as the sum of two abundant numbers."
]
},
```
Don't be confused now, here's what to do to improve the problems:
(We expect you already have forked freeCodeCamp's repository)
### Step 1: Create new branch at your git origin (e.g: `feature/problem_euler23`)
Always create the branch with the base refer to the newest freeCodeCamp's
staging branch, here's how to do that:
1. Do fetch staging branch from freeCodeCamp's repository `$ git fetch upstream
staging`
2. Checkout to the staging branch `$ git checkout upstream/staging`
3. Create branch from upstream/staging `$ git checkout -b <branch_name>`
### Step 2: Change the name of the function to more readable
For example, from `euler23()` into `sumOfNonAbundantNumbers()` We took the name
from the problem name :D
### Step 3: Solve the problem by yourself
Try to solve the problem by yourself but if you get stucked,
Here's what to do: you can go to [mathblog](http://www.mathblog.dk/) or
[dreamshire](https://blog.dreamshire.com) to find other people's solution
written in other languages (usually C and C#) Learn from their solution and port
it to JavaScript :) ( Always have the perspective of learning, don't just copy
paste other people's code )
So from the example here's my solution (We didn't include it in the JSON because
up till now, we couldn't find a way to fit it in, when we transformed it into
array of strings it spits out error when running `$ npm run test-challenges` it
will be awesome if you can find how to fits that right in)
```javascript
function sumOfNonAbundantNumbers() {
const getFactors = number => {
let factors = [];
let possibleFactor = 1;
let sqrt = Math.sqrt(number);
while (possibleFactor <= sqrt) {
if (number % possibleFactor == 0) {
factors[factors.length] = possibleFactor;
let otherPossibleFactor = number / possibleFactor;
if (otherPossibleFactor > possibleFactor)
factors[factors.length] = otherPossibleFactor;
}
possibleFactor++;
}
return factors;
};
const getAbundantNumbers = upperLimit => {
let abundantNumbers = [];
for (let i = 12; i <= upperLimit; i++) {
let factors = getFactors(i);
let factorSum = 0;
for (let factor, j = 0; (factor = factors[j]); j++)
if (i != factor) factorSum += factor;
if (factorSum > i) {
abundantNumbers.push(i);
}
}
return abundantNumbers;
};
var abundantNumbers = getAbundantNumbers(28123);
var sum = 0;
for (var testNum = 1; testNum <= 28123; testNum++) {
var sumOfAbundant = false;
for (
var i = 0, j = abundantNumbers.length - 1, abundantNumber1;
(abundantNumber1 = abundantNumbers[i]);
i++
) {
if (abundantNumber1 > testNum) {
break;
}
var abundantNumber2 = abundantNumbers[j];
while (j > 0 && abundantNumber1 + abundantNumber2 > testNum) {
abundantNumber2 = abundantNumbers[--j];
}
if (abundantNumber1 + abundantNumber2 == testNum) {
sumOfAbundant = true;
break;
}
}
if (!sumOfAbundant) {
sum += testNum;
}
}
return sum;
}
```
After finished solving the problem, you can improve the task a little bit, for
example compared to asking campers to find the sum of all the positive integers,
you can ask campers to find the sum of all positive integers <= n.
(if you add more assertions to the problem, always assert less than the original
problem, to prevent infinite loop, etc)
One last thing, always make sure that the return value of the function is always
the same data type to which you want the function to return
Like in the example above, we want the user to return integer, so we changed the
return value from true into integer.
### Step 4: Running Test on Arcade Mode
After done with the solution, run the test on
[ FCC's Arcade Mode ](https://github.com/freeCodeCamp/arcade-mode)
### Step 5: Commit changes and push to your origin
1. Do changes and add changed files to stage `$ git add .`
2. Commit those changes using `$ npm run commit` and follow the instruction
there.
3. And run `$ git push origin <branch_name>`
### Step 5: Create Pull Request to freeCodeCamp's staging branch
Create PR to freeCodeCamp's staging branch and wait for your code to be assesed
from the maintainer.
That's all it! if there's something unclear and you still have questions, you
can chat from gitter in
[Arcade-Mode](https://gitter.im/FreeCodeCamp/arcade-mode)
[Contributors](https://gitter.im/FreeCodeCamp/Contributors) or you can text me
right away @alvinkl
# Why do we have to improve Project Euler problems?
Our goal is to prevent user from cheating and just returning the project euler
result rightaway, and by giving more assertions and improving a bit of the task
we are able to make the challenge more challenging as well.
With your help, we can help people to practice their skills and be confident to
face technical interviews like this :)

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,829 @@
{
"name": "Take Home Projects",
"order": 4,
"time": "",
"helpRoom": "HelpFrontEnd",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd10",
"title": "Show the Local Weather",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"<strong>Rule #1:</strong> Don't look at the example project's code. Figure it out for yourself.",
"<strong>Rule #2:</strong> Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see the weather in my current location.",
"<strong>User Story:</strong> I can see a different icon or background image (e.g. snowy mountain, hot desert) depending on the weather.",
"<strong>User Story:</strong> I can push a button to toggle between Fahrenheit and Celsius.",
"<strong>Note:</strong> Many internet browsers now require an HTTP Secure (<code>https://</code>) connection to obtain a user's locale via HTML5 Geolocation. For this reason, we recommend using HTML5 Geolocation to get user location and then use the freeCodeCamp Weather API <a href='https://fcc-weather-api.glitch.me' target='_blank'>https://fcc-weather-api.glitch.me</a> which uses an HTTP Secure connection for the weather. Also, be sure to connect to <a href='https://codepen.io' target='_blank'>CodePen.io</a> via <code>https://</code>.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Muestra el clima local",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites.",
"<span class='text-info'>Historia de usuario:</span> Pedo obtener información acerca del clima en mi localización actual.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver un icono diferente o una imagen de fondo diferente (e.g. montaña con nieve, desierto caliente) dependiendo del clima.",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar un botón para cambiar la unidad de temperatura de grados Fahrenheit a Celsius y viceversa.",
"Recomendamos utilizar <a href='https://openweathermap.org/current#geo' target='_blank'>Open Weather API</a>. Al utilizarlo tendrás que crear una llave API gratuita. Normalmente debes evitar exponer llaves de API en CodePen, pero por el momento no hemos encontrado un API de clima que no requiera llave.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Покажите местную погоду",
"description": [
"<span class='text-info'>Задание:</span> Создайте <a href='https://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='https://codepen.io/freeCodeCamp/full/bELRjV' target='_blank'>https://codepen.io/freeCodeCamp/full/bELRjV</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу узнать погоду с учетом моего текущего местоположения.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу в зависимости от погоды видеть различные температурные значки.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу в зависимости от погоды видеть различные фоновые изображения (снежные горы, знойная пустыня).",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу нажать на кнопку чтобы переключится между градусами по Цельсию или по Фаренгейту.",
"Если что-то не получается, воспользуйтесь <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a>.",
"Когда выполните задание кликните кнопку \"I've completed this challenge\" и добавьте ссылку на ваш CodePen. Если вы программировали с кем-то в паре, также добавьте имя вашего напарника.",
"Если вы хотите получить немедленную оценку вашего проекта, нажмите эту кнопку и добавьте ссылку на ваш CodePen. В противном случае мы проверим его перед тем как вы приступите к проектам для некоммерческих организаций.<br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd19",
"title": "Build a Wikipedia Viewer",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/wGqEga/' target='_blank'>https://codepen.io/freeCodeCamp/full/wGqEga/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can search Wikipedia entries in a search box and see the resulting Wikipedia entries.",
"<strong>User Story:</strong> I can click a button to see a random Wikipedia entry.",
"<span class='text-info'>Hint #1:</span> Here's a URL you can use to get a random Wikipedia article: <code>https://en.wikipedia.org/wiki/Special:Random</code>.",
"<span class='text-info'>Hint #2:</span> Here's an entry on using Wikipedia's API: <code>https://www.mediawiki.org/wiki/API:Main_page</code>.",
"<span class='text-info'>Hint #3:</span> Use this <a href='https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=jsonfm' target='_blank'>link</a> to experiment with Wikipedia's API.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Crea un buscador de Wikipedia",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/wGqEga/' target='_blank'>https://codepen.io/freeCodeCamp/full/wGqEga/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Pedo obtener información acerca del clima en mi localización actual.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver un icono diferente o una imagen de fondo diferente (e.g. montaña con nieve, desierto caliente) dependiendo del clima.",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar un botón para cambiar la unidad de temperatura de grados Fahrenheit a Celsius y viceversa.",
"<span class='text-info'>Historia de usuario:</span> Puedo buscar entradas en Wikipedia en un cuadro de búsqueda y ver las entradas de Wikipedia resultantes.",
"<span class='text-info'>Historia de usuario:</span>Puedo pulsar un botón para ver un artículo aleatorio de Wikipedia.",
"<span class='text-info'>Pista 1:</span> Aquí está una URL donde puedes ver una entrada aleatoria de Wikipedia: <code>https://en.wikipedia.org/wiki/Special:Random<</code>.",
"<span class='text-info'>Pista 2:</span> Este es un artículo muy útil relativo al uso del API de Wikipedia: <code>https://www.mediawiki.org/wiki/API:Main_page</code>.",
"<span class='text-info'>Pista 3:</span> Usa este <a href='https://en.wikipedia.org/wiki/Special:ApiSandbox#action=query&titles=Main%20Page&prop=revisions&rvprop=content&format=jsonfm' target='_blank'>enlace</a> para experimentar con el API de Wikipedia.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd1f",
"title": "Use the Twitch JSON API",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see whether freeCodeCamp is currently streaming on Twitch.tv.",
"<strong>User Story:</strong> I can click the status output and be sent directly to the freeCodeCamp's Twitch.tv channel.",
"<strong>User Story:</strong> if a Twitch user is currently streaming, I can see additional details about what they are streaming.",
"<strong>Hint:</strong> See an example call to Twitch.tv's JSONP API at <a href='http://forum.freecodecamp.org/t/use-the-twitchtv-json-api/19541' target='_blank'>http://forum.freecodecamp.org/t/use-the-twitchtv-json-api/19541</a>.",
"<strong>Hint:</strong> The relevant documentation about this API call is here: <a href='https://dev.twitch.tv/docs/v5/reference/streams/#get-stream-by-user' target='_blank'>https://dev.twitch.tv/docs/v5/reference/streams/#get-stream-by-user</a>.",
"<strong>Hint:</strong> Here's an array of the Twitch.tv usernames of people who regularly stream: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"<strong>UPDATE:</strong> Due to a change in conditions on API usage explained <a href='https://blog.twitch.tv/client-id-required-for-kraken-api-calls-afbb8e95f843#.f8hipkht1' target='_blank'>here</a> Twitch.tv now requires an API key, but we've built a workaround. Use <a href='https://wind-bow.glitch.me' target='_blank'>https://wind-bow.glitch.me/twitch-api</a> instead of twitch's API base URL (i.e. https://api.twitch.tv/kraken ) and you'll still be able to get account information, without needing to sign up for an API key.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Usa el API JSON de Twitch",
"description": [
"<span class='text-info'>Objetivo:</span> Crea una aplicación con <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Puedo verificar si freeCodeCamp está transmitiendo actualmente en Twitch.tv",
"<span class='text-info'>Historia de usuario:</span> Puedo pulsar el estatus y ser enviado directamente al canal de freeCodeCamp en Twitch.tv.",
"<span class='text-info'>Historia de usuario:</span> Si un usuario Twitch está transmitiendo actualmente, puedo ver detalles adicionales acerca del contenido que están transmitiendo.",
"<span class='text-info'>Pista:</span> Obseva una llamada de ejemplo al API JSONP de Twitch.tv en <code>http://forum.freecodecamp.org/t/use-the-twitchtv-json-api/19541</code>.",
"<span class='text-info'>Pista:</span> La documentación relevante sobre esta llamada al API está aquí: <a href='https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel' target='_blank'>https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel</a>.",
"<span class='text-info'>Pista:</span> Aquí está un vector de usuarios en Twitch.tv que regularmente transmiten sobre programación: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Используйте Twitch JSON API",
"description": [
"<span class='text-info'>Задание:</span> Создайте <a href='https://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='https://codepen.io/freeCodeCamp/full/Myvqmo/' target='_blank'>https://codepen.io/freeCodeCamp/full/Myvqmo/</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу увидеть идет ли в данный момент на Twitch.tv трансляция freeCodeCamp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу, кликнув на описание трансляции, перейти на канал freeCodeCamp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу видеть дополнительную информацию о текущей трансляции freeCodeCamp.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу произвести поиск среди перечисленных каналов.",
"<span class='text-info'>Подсказка:</span> Пример запроса к Twitch.tv JSON API: <code>https://api.twitch.tv/kraken/streams/freecodecamp</code>.",
"<span class='text-info'>Подсказка:</span> Документацию об этом запросе можно найти по ссылке: <a href='https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel' target='_blank'>https://github.com/justintv/Twitch-API/blob/master/v3_resources/streams.md#get-streamschannel</a>.",
"<span class='text-info'>Подсказка:</span> В этом массиве приведены имена пользователей, которые регулярно пишут код онлайн: <code>[\"ESL_SC2\", \"OgamingSC2\", \"cretetion\", \"freecodecamp\", \"storbeck\", \"habathcx\", \"RobotCaleb\", \"noobs2ninjas\"]</code>",
"Если что-то не получается, воспользуйтесь <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a>.",
"Когда выполните задание кликните кнопку \"I've completed this challenge\" и добавьте ссылку на ваш CodePen. Если вы программировали с кем-то в паре, также добавьте имя вашего напарника.",
"Если вы хотите получить немедленную оценку вашего проекта, нажмите эту кнопку и добавьте ссылку на ваш CodePen. В противном случае мы проверим его перед тем как вы приступите к проектам для некоммерческих организаций.<br><br><a class='btn btn-primary btn-block' href='https://twitter.com/intent/tweet?text=Check%20out%20the%20project%20I%20just%20built%20with%20%40FreeCodeCamp:%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
]
}
}
},
{
"id": "bd7158d8c443edefaeb5bdee",
"title": "Build an Image Search Abstraction Layer",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that allows you to search for images like this: <a href='https://cryptic-ridge-9197.herokuapp.com/api/imagesearch/lolcats%20funny?offset=10' target='_blank'>https://cryptic-ridge-9197.herokuapp.com/api/imagesearch/lolcats%20funny?offset=10</a> and browse recent search queries like this: <a href='https://cryptic-ridge-9197.herokuapp.com/api/latest/imagesearch/' target='_blank'>https://cryptic-ridge-9197.herokuapp.com/api/latest/imagesearch/</a>. Then deploy it to Glitch.",
"Note that for each project, you should create a new GitHub repository and a new Glitch project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-api-development-projects'>https://freecodecamp.org/challenges/get-set-for-our-api-development-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> I can get the image URLs, alt text and page urls for a set of images relating to a given search string.",
"<strong>User Story:</strong> I can paginate through the responses by adding a ?offset=2 parameter to the URL.",
"<strong>User Story:</strong> I can get a list of the most recently submitted search strings.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Glitch.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"isRequired": true,
"releasedOn": "January 1, 2016",
"challengeType": 4,
"translations": {
"es": {
"title": "Capa de abstracción para buscar imágenes",
"description": [
"<strong>Objetivo:</strong> Desarolla una aplicación de Pila Completa en JavaScript que te permite buscar imágenes como esta: <a href='https://cryptic-ridge-9197.herokuapp.com/api/imagesearch/lolcats%20funny?offset=10' target='_blank'>https://cryptic-ridge-9197.herokuapp.com/api/imagesearch/lolcats%20funny?offset=10</a> y examinar las búsquedas recientes como esta: <a href='https://cryptic-ridge-9197.herokuapp.com/api/latest/imagesearch/' target='_blank'>https://cryptic-ridge-9197.herokuapp.com/api/latest/imagesearch/</a>. Después, despliegala en Glitch.",
"Ten en cuenta que para cada proyecto, deberías crear un nuevo repositorio en GitHub y un nuevo proyecto en Glitch. Si no recuerdas como hacer esto, vuelve a visitar <a href='/challenges/get-set-for-our-api-development-projects'>https://freecodecamp.org//challenges/get-set-for-our-api-development-projects</a>.",
"Aquí están las historias de usuario específicas que debes implementar para este proyecto:",
"<strong>Historia de Usuario:</strong> Puedo obtener la URL de una imagen, texto alternativo y URLs de las páginas de un conjunto de imágenes que se relacionen con una cadena de texto dada.",
"<strong>Historia de Usuario:</strong> Puedo examinar página a página las respuestas añadiendo un parámetro del estilo <code>?offset=2</code> al URL.",
"<strong>Historia de Usuario:</strong> Puedo obtener una lista de las cadenas búscadas que se enviaron más recientemente.",
"Una vez que hayas terminado de implementar estas historias de usuarios, pulsa el botón \"I've completed this challenge\" e introduce los URLs de tu repositorio en GitHub y de tu aplicación en vivo en Glitch.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiendolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c442eedfaeb5bd1c",
"title": "Build a Tic Tac Toe Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/KzXQgy/' target='_blank'>https://codepen.io/freeCodeCamp/full/KzXQgy/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can play a game of Tic Tac Toe with the computer.",
"<strong>User Story:</strong> My game will reset as soon as it's over so I can play again.",
"<strong>User Story:</strong> I can choose whether I want to play as X or O.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Crea un juego de Tic Tac Toe",
"description": [
"<span class='text-info'>Objetivo:</span> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/freeCodeCamp/full/KzXQgy/' target='_blank'>https://codepen.io/freeCodeCamp/full/KzXQgy/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Puedo jugar un juego de Tic Tac Toe contra el computador.",
"<span class='text-info'>Historia de usuario:</span> Mi juego se reiniciará tan pronto como termine para poder jugar de nuevo.",
"<span class='text-info'>Historia de usuario:</span> Puedo elegir si quiero jugar como X o como O.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiéndolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c442eddfaeb5bd1c",
"title": "Build a Simon Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/Em-Ant/full/QbRyqq/' target='_blank'>https://codepen.io/freeCodeCamp/full/obYBjE</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I am presented with a random series of button presses.",
"<strong>User Story:</strong> Each time I input a series of button presses correctly, I see the same series of button presses but with an additional step.",
"<strong>User Story:</strong> I hear a sound that corresponds to each button both when the series of button presses plays, and when I personally press a button.",
"<strong>User Story:</strong> If I press the wrong button, I am notified that I have done so, and that series of button presses starts again to remind me of the pattern so I can try again.",
"<strong>User Story:</strong> I can see how many steps are in the current series of button presses.",
"<strong>User Story:</strong> If I want to restart, I can hit a button to do so, and the game will return to a single step.",
"<strong>User Story:</strong> I can play in strict mode where if I get a button press wrong, it notifies me that I have done so, and the game restarts at a new random series of button presses.",
"<strong>User Story:</strong> I can win the game by getting a series of 20 steps correct. I am notified of my victory, then the game starts over.",
"<strong>Hint:</strong> Here are mp3s you can use for each button: <code>https://s3.amazonaws.com/freecodecamp/simonSound1.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound2.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound3.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound4.mp3</code>.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"translations": {
"es": {
"title": "Construye un juego de Simon",
"description": [
"<span class='text-info'>Objetivo:</span> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> cuya funcionalidad sea similar a la de esta: <a href='https://codepen.io/Em-Ant/full/QbRyqq/' target='_blank'>https://codepen.io/Em-Ant/full/QbRyqq/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o APIs que necesites. Dale tu estilo personal.",
"<span class='text-info'>Historia de usuario:</span> Se me presenta una serie aleatoria de pulsaciones a botones.",
"<span class='text-info'>Historia de usuario:</span> Cada vez que presiono una secuencia de pulsaciones correctamente, veo que vuelve a ejecutarse la misma serie de pulsaciones con un paso adicional.",
"<span class='text-info'>Historia de usuario:</span> Escucho un sonido que corresponde a cada botón cuando se ejecuta una secuencia de pulsaciones, así como cuando yo presiono un botón.",
"<span class='text-info'>Historia de usuario:</span> Si presiono el botón equivocado, se me notifica sobre mi error, y se ejecuta de nuevo la serie correcta de pulsaciones para recordarme cuál es la secuencia correcta, tras lo cual puedo intentar de nuevo.",
"<span class='text-info'>Historia de usuario:</span> Puedo ver cuántos pasos hay en la serie de pulsaciones actual.",
"<span class='text-info'>Historia de usuario:</span> Si deseo reiniciar, puedo pulsar un botón para hacerlo, y el juego comenzará desde una secuencia con un solo paso.",
"<span class='text-info'>Historia de usuario:</span> Puedo jugar en modo estricto donde si presiono el botón equivocado, se me notifica de mi error, y el juego vuelve a comenzar con una nueva serie aleatoria de colores.",
"<span class='text-info'>Historia de usuario:</span> Puedo ganar el juego si completo 20 pasos correctos. Se me notifica sobre mi victoria, tras lo cual el juego se reinicia.",
"<span class='text-info'>Pista:</span> Aquí hay algunos mp3s que puedes utilizar para tus botones: <code>https://s3.amazonaws.com/freecodecamp/simonSound1.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound2.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound3.mp3</code>, <code>https://s3.amazonaws.com/freecodecamp/simonSound4.mp3</code>.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Leer-Buscar-Preguntar</a> si te sientes atascado.",
"Cuando hayas terminado, pulsa el botón de \"I've completed this challenge\" e incluye un enlace a tu CodePen.",
"Puedes obtener retroalimentación sobre tu proyecto por parte de otros campistas, compartiéndolo en nuestra <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Sala de chat para revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7156d8c242eddfaeb5bd13",
"title": "Build a Camper Leaderboard",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see a table of the freeCodeCamp campers who've earned the most brownie points in the past 30 days.",
"<strong>User Story:</strong> I can see how many brownie points they've earned in the past 30 days, and how many they've earned total.",
"<strong>User Story:</strong> I can toggle between sorting the list by how many brownie points they've earned in the past 30 days and by how many brownie points they've earned total.",
"<strong>Hint:</strong> To get the top 100 campers for the last 30 days: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Hint:</strong> To get the top 100 campers of all time: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"tests": [],
"isRequired": false,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un marcador para los campistas",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Historia de usuario:</strong> Puedo ver un tablero con los campistas de freeCodeCamp que han ganado más puntos de brownie en los últimos 30 días.",
"<strong>Historia de usuario:</strong> Puedo ver cuántos puntos de brownie han ganado en los últimos 30 días, y cuántos han ganado en total.",
"<strong>Historia de usuario:</strong> Puedo elegir entre dos formas de organizar la lista: 1) En base a cuántos puntos de brownie se han ganado en los últimos 30 días. 2) En base al número de puntos de brownie que han ganado en total.",
"<strong>Pista:</strong> Para obtener los 100 mejores campistas para los últimos 30 días: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Pista:</strong> Para obtener los 100 mejores campistas de toda la historia: <a href='http://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>http://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Создайте таблицу Кемперов-Лидеров",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/eZGMjp/' target='_blank'>https://codepen.io/freeCodeCamp/full/eZGMjp/</a>.",
"Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Пользовательская история:</strong> Я могу видеть таблицу кемперов freeCodeCamp, которые получили наибольшее количество очков за последние 30 дней.",
"<strong>Пользовательская история:</strong> Я могу видеть сколько очков они получили за последние 30 дней, и сколько они получили их всего.",
"<strong>Пользовательская история:</strong> Я могу отсортировать список по количеству очков, которые они получили за последние 30 дней, и по общему количеству полученных очков.",
"<strong>Подсказка:</strong> Ссылка на топ 100 кемперов за последние 30 дней в формате JSON: <a href='https://fcctop100.herokuapp.com/api/fccusers/top/recent' target='_blank'>https://fcctop100.herokuapp.com/api/fccusers/top/recent</a>.",
"<strong>Подсказка:</strong> Ссылка на топ 100 кемперов за все время в формате JSON: <a href='http://fcctop100.herokuapp.com/api/fccusers/top/alltime' target='_blank'>http://fcctop100.herokuapp.com/api/fccusers/top/alltime</a>.",
"Если что-то не получается, не забывайте пользоваться методом <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице freeCodeCamp вашего города на Facebook."
]
}
}
},
{
"id": "bd7155d8c242eddfaeb5bd13",
"title": "Build a Recipe Box",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can create recipes that have names and ingredients.",
"<strong>User Story:</strong> I can see an index view where the names of all the recipes are visible.",
"<strong>User Story:</strong> I can click into any of those recipes to view it.",
"<strong>User Story:</strong> I can edit these recipes.",
"<strong>User Story:</strong> I can delete these recipes.",
"<strong>User Story:</strong> All new recipes I add are saved in my browser's local storage. If I refresh the page, these recipes will still be there.",
"<strong>Hint: </strong> You should prefix your local storage keys on CodePen, i.e. <code>_username_recipes</code>",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"tests": [],
"isRequired": false,
"challengeType": 3,
"translations": {
"ru": {
"title": "Создайте хранилище рецептов",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"<strong>Правило #1:</strong> Не подсматривайте код приложения-примера. Напишите его самостоятельно.",
"<strong>Правило #2:</strong> Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Правило #3:</strong> Для создания этого проекта вы должны использовать Sass и React.",
"<strong>Пользовательская история:</strong> Я могу создавать рецепты, содержащие название и ингредиенты.",
"<strong>Пользовательская история:</strong> Я могу просмотреть корневой вид, на котором видны все рецепты.",
"<strong>Пользовательская история:</strong> Я могу нажать на имя каждого из рецептов для просмотра содержимого.",
"<strong>Пользовательская история:</strong> Я могу отредактировать эти рецепты.",
"<strong>Пользовательская история:</strong> Я могу удалить эти рецепты.",
"<strong>Пользовательская история:</strong> Все новые рецепты, которые я добавил, сохранены в локальном хранилище моего браузера. Если я обновлю страницу, эти рецепты будут всё ещё там.",
"Если что-то не получается, не забывайте пользоваться методом <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице Free Code Camp вашего города на Facebook."
]
},
"es": {
"title": "Crea una caja de recetas",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/dNVazZ/' target='_blank'>https://codepen.io/freeCodeCamp/full/dNVazZ/</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Rule #3:</strong> Debes utilizar ambos Sass y React para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo crear recetas a las que les puedo poner un nombre y los ingredientes necesarios.",
"<strong>Historia de usuario:</strong> Puedo ver un índice que contenga los nombres de todas las recetas.",
"<strong>Historia de usuario:</strong> Puedo pulsar cualquiera de las recetas para verla.",
"<strong>Historia de usuario:</strong> Puedo editar las recetas.",
"<strong>Historia de usuario:</strong> Puedo eliminar las recetas.",
"<strong>Historia de usuario:</strong> Las recetas que voy agregando deben guardarse en el almacenamiento local de mi navegador. Las recetas deben seguir allí si refresco la página.",
"Recuerda utilizar <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7154d8c242eddfaeb5bd13",
"title": "Build the Game of Life",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> When I first arrive at the game, it will randomly generate a board and start playing.",
"<strong>User Story:</strong> I can start and stop the board.",
"<strong>User Story:</strong> I can set up the board.",
"<strong>User Story:</strong> I can clear the board.",
"<strong>User Story:</strong> When I press start, the game will play out.",
"<strong>User Story:</strong> Each time the board changes, I can see how many generations have gone by.",
"<strong>Hint:</strong> Here's an explanation of Conway's Game of Life from John Conway himself: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Hint:</strong> Here's an overview of Conway's Game of Life with rules for your reference: <a href='https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life' target='_blank'>https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life</a>",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"tests": [],
"isRequired": false,
"challengeType": 3,
"translations": {
"ru": {
"title": "Создайте игру \"Жизнь\"",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"<strong>Правило #1:</strong> Не подсматривайте код приложения-примера. Напишите его самостоятельно.",
"<strong>Правило #2:</strong> Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Правило #3:</strong> Для создания этого проекта вы должны использовать Sass и React.",
"<strong>Пользовательская история:</strong> Когда я впервые запускаю игру, она генерирует доску случайным образом и начинает игру.",
"<strong>Пользовательская история:</strong> Я могу запустить и остановить игру.",
"<strong>Пользовательская история:</strong> Я могу настроить доску.",
"<strong>Пользовательская история:</strong> Я могу очистить доску.",
"<strong>Пользовательская история:</strong> Когда я нажимаю начать, игра начинает воспроизведение.",
"<strong>Пользовательская история:</strong> Каждый раз, когда доска меняется, я могу видеть сколько поколений прошло.",
"<strong>Подсказка:</strong> Вот объяснение игры \"Жизнь\" от её создателя Джона Конвея: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Подсказка:</strong> Вот обзор правил игры \"Жизнь\" для вашего сведения: <a href='https://ru.wikipedia.org/wiki/Жизнь_(игра)' target='_blank'>https://ru.wikipedia.org/wiki/Жизнь_(игра)</a>",
"Если что-то не получается, не забывайте пользоваться методом <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице Free Code Camp вашего города на Facebook."
]
},
"es": {
"title": "Crea un Juego de la vida",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/BpwMZv/' target='_blank'>https://codepen.io/freeCodeCamp/full/BpwMZv/</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Rule #3:</strong> Debes utilizar ambos Sass y React para construir este proyecto.",
"<strong>Historia de usuario:</strong> La aplicación debe generar aleatoriamente un tablero y comenzar a jugar cuando entro al juego por primera vez.",
"<strong>Historia de usuario:</strong> Puedo iniciar y detener el tablero.",
"<strong>Historia de usuario:</strong> Puedo preparar el tablero.",
"<strong>Historia de usuario:</strong> Puedo limpiar el tablero.",
"<strong>Historia de usuario:</strong> El juego inicia cuando presiono un botón de inicio.",
"<strong>Historia de usuario:</strong> Puedo ver cuántas generaciones han pasado cada vez que el tablero cambia.",
"<strong>Pista:</strong> Puedes encontrar una explicación del Juego de la vida de Conway de parte del mismísimo John Conway aquí: <a href='https://www.youtube.com/watch?v=E8kUJL04ELA' target='_blank'>https://www.youtube.com/watch?v=E8kUJL04ELA</a>",
"<strong>Pista:</strong> Puedes referirte al siguiente enlace para obtener información general acerca del Juego de la vida de Conway incluyendo las reglas del juego: <a href='https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life' target='_blank'>https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life</a>",
"Recuerda utilizar <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/FreeCodeCamp-Get-Help' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7153d8c242eddfaeb5bd13",
"title": "Build a Roguelike Dungeon Crawler Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I have health, a level, and a weapon. I can pick up a better weapon. I can pick up health items.",
"<strong>User Story:</strong> All the items and enemies on the map are arranged at random.",
"<strong>User Story:</strong> I can move throughout a map, discovering items.",
"<strong>User Story:</strong> I can move anywhere within the map's boundaries, but I can't move through an enemy until I've beaten it.",
"<strong>User Story:</strong> Much of the map is hidden. When I take a step, all spaces that are within a certain number of spaces from me are revealed.",
"<strong>User Story:</strong> When I beat an enemy, the enemy goes away and I get XP, which eventually increases my level.",
"<strong>User Story:</strong> When I fight an enemy, we take turns damaging each other until one of us loses. I do damage based off of my level and my weapon. The enemy does damage based off of its level. Damage is somewhat random within a range.",
"<strong>User Story:</strong> When I find and beat the boss, I win.",
"<strong>User Story:</strong> The game should be challenging, but theoretically winnable.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"releasedOn": "January 1, 2016",
"tests": [],
"isRequired": false,
"challengeType": 3,
"translations": {
"es": {
"title": "Crea un juego de dragones al estilo Rogue",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Historia de usuario:</strong> Tengo energía, nivel de habilidad y un arma. Puedo recoger un arma mejor. Puedo recoger ítems que recuperan mi energía.",
"<strong>Historia de usuario:</strong> Todos los ítems y los enemigos en el mapa están colocados aleatoriamente.",
"<strong>Historia de usuario:</strong> Puedo moverme a lo largo de un mapa y descubrir ítems.",
"<strong>Historia de usuario:</strong> Puedo moverme hacia cualquier parte dentro de los límites del mapa, pero no puedo moverme sobre un enemigo hasta que lo haya vencido.",
"<strong>Historia de usuario:</strong> Gran parte del mapa está escondido. Cuando doy un paso, todos los espacios que están a cierto número de espacios de distancia de mi son revelados.",
"<strong>Historia de usuario:</strong> Cuando venzo un enemigo, este desaparece y yo gano puntos de experiencia (XP), lo que eventualmente me permite aumentar de nivel.",
"<strong>Historia de usuario:</strong> Cuando peleo con un enemigo, tomamos turnos haciéndonos daño hasta que uno de los dos pierde. El daño que hago está basado en mi nivel de experiencia y en el arma que estoy utilizando. El enemigo hace daño basado en su nivel. El daño es aleatorio dentro de cierto márgen.",
"<strong>Historia de usuario:</strong> Gano el juego cuando encuentre y venza al jefe.",
"<strong>Historia de usuario:</strong> El juego debe representar un reto, pero ganar debe ser teóricamente posible.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
},
"ru": {
"title": "Создайте Roguelike-подобную игру Подземелье",
"description": [
"<strong>Задание:</strong> Создайте приложение <a href='https://codepen.io' target='_blank'>CodePen.io</a>, функционал которого схож с этим: <a href='https://codepen.io/freeCodeCamp/full/apLXEJ/' target='_blank'>https://codepen.io/freeCodeCamp/full/apLXEJ/</a>.",
"Приложение должно удовлетворять нижеприведённым <a href='https://ru.wikipedia.org/wiki/Пользовательскиестории' target='_blank'>пользовательским историям</a>. Используйте любые библиотеки или API, которые потребуются. Придайте ему свой личный стиль.",
"<strong>Пользовательская история:</strong> У меня есть жизни, уровень и оружие. Я могу подобрать оружие получше. Я могу подобрать очки здоровья.",
"<strong>Пользовательская история:</strong> Все предметы и враги располагаются на карте случайным образом.",
"<strong>Пользовательская история:</strong> Я могу передвигаться по карте, обнаруживая новые предметы.",
"<strong>Пользовательская история:</strong> Я могу двигаться куда угодно в рамках карты, но не могу продвинуться дальше врага, пока он не будет побежден.",
"<strong>Пользовательская история:</strong> Большая часть карты скрыта. Когда я делаю шаг, все клетки в определенном количестве клеток от меня становятся видимы.",
"<strong>Пользовательская история:</strong> Когда я побеждаю врага, враг исчезает, а я получаю очки опыта (XP), что увеличивает мой уровень.",
"<strong>Пользовательская история:</strong> Когда я веду бой с врагом, мы поочередно наносим друг-другу повреждения, до тех пор пока кто-нибудь не победит. Я наношу повреждения, которые зависят от моего уровня и моего оружия. Враг наносит повреждения, которые зависят от его уровня. Значение повреждений распределено случайным образом в некотором диапазоне.",
"<strong>Пользовательская история:</strong> Когад я нахожу и побеждаю босса, я выигрываю игру.",
"<strong>Пользовательская история:</strong> Игра должна быть интересной и достаточно сложной, но теоретически проходимой.",
"Если что-то не получается, не забывайте пользоваться методом <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Читай-Ищи-Спрашивай</a>.",
"Когда закончите, нажмите кнопку \"I've completed this challenge\" и укажите ссылку на вашу работу на CodePen.",
"Вы можете получить отзыв о вашем проекте от коллег, поделившись ссылкой на него в нашем <a href='//gitter.im/freecodecamp/codereview' target='_blank'>чате для рассмотрения кода</a>. Также вы можете поделиться ею через Twitter и на странице freeCodeCamp вашего города на Facebook."
]
}
}
},
{
"id": "bd7150d8c442eddfafb5bd1c",
"title": "P2P Video Chat Application",
"description": [
"<strong>Objective:</strong> Build a <a href='https://glitch.com' target='_blank'>Glitch</a> app that is functionally similar to this: <a href='https://grove-voice.glitch.me/' target='_blank'>https://grove-voice.glitch.me</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> Upon arriving, the browser will prompt me to access my camera and microphone. ",
"<strong>User Story:</strong> After I give it permission, I am prompted to type in a room name.",
"<strong>User Story:</strong> Once I type in the room name, a room will be created if no room of that name existed before. ",
"<strong>User Story:</strong> A friend of mine can subsequently go to the same website, type in the same room I entered, and join the same room, then enter into a video chat with me. ",
"<strong>User Story:</strong> If I type in a room name, and there are already two people in that room, I get a notification that the room is full. ",
"<strong>User Story:</strong> Anyone can create or join any room. And there can be any number of rooms, but all of them must have unique names. ",
"<strong>User Story:</strong> I can choose to not permit the site to access my microphone and webcam. If I choose not to do this, if some other driver problem occurs, I see an error message saying these are required. ",
"<strong>User Story:</strong> When I choose to cancel the room name input step, or if I type in no name, or just spaces, it should again ask me again to type in a valid room name. ",
"<strong>User Story:</strong> If one of the two people in the room get disconnected, they can reconnect to the same room and continue chatting.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your Glitch App.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false,
"releasedOn": "January 1, 2016"
},
{
"id": "bd7198d8c242eddfaeb5bd13",
"title": "Show National Contiguity with a Force Directed Graph",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/xVopBo' target='_blank'>https://codepen.io/freeCodeCamp/full/xVopBo</a>.",
"Fulfill the following <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see a Force-directed Graph that shows which countries share borders.",
"<strong>User Story:</strong> I can see each country's flag on its node.",
"<strong>Hint:</strong> Here's a dataset you can use to build this: <a href='https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json' target='_blank'>https://raw.githubusercontent.com/DealPete/forceDirected/master/countries.json</a>",
"<strong>Hint:</strong> You can create a spritesheet of national flags at <a href='https://www.flag-sprites.com' target='_blank'>https://www.flag-sprites.com</a>.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"isRequired": false,
"releasedOn": "January 1, 2016",
"challengeType": 3,
"translations": {
"es": {
"title": "Muestra asociaciones utilizando un gráfico de fuerzas dirigidas",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/KVNNXY' target='_blank'>https://codepen.io/freeCodeCamp/full/KVNNXY</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Regla #3:</strong> Debes utilizar D3.js para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo ver un gráfico de fuerza dirigida que muestra qué campistas están publicando enlaces en Camper News hacia qué dominios.",
"<strong>Historia de usuario:</strong> Puedo ver el icono de cada campista en su nodo respectivo.",
"<strong>Historia de usuario:</strong> Puedo ver la relación entre los campistas y los dominios que publican.",
"<strong>Historia de usuario:</strong> Puedo conocer aproximadamente cuántas veces los campistas han enlazado un dominio en particular a partir del tamaño del nodo respectivo.",
"<strong>Historia de usuario:</strong> Puedo conocer aproximadamente cuántas veces un campista específico ha publicado un enlace a partir del tamaño de su nodo.",
"<strong>Pista:</strong> La siguiente es la ruta del API de noticias de Camper News: <code>http://www.freecodecamp.org/news/hot</code>.",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7108d8c242eddfaeb5bd13",
"title": "Map Data Across the Globe",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/mVEJag' target='_blank'>https://codepen.io/freeCodeCamp/full/mVEJag</a>.",
"Fulfill the following <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can see where all Meteorites landed on a world map.",
"<strong>User Story:</strong> I can tell the relative size of the meteorite, just by looking at the way it's represented on the map.",
"<strong>User Story:</strong> I can mouse over the meteorite's data point for additional data.",
"<strong>Hint:</strong> Here's a dataset you can use to build this: <a href='https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json' target='_blank'>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json</a>",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen. ",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"isRequired": false,
"releasedOn": "January 1, 2016",
"challengeType": 3,
"translations": {
"es": {
"title": "Mapea datos a lo largo del Globo",
"description": [
"<strong>Objetivo:</strong> Construye una aplicación en <a href='https://codepen.io' target='_blank'>CodePen.io</a> que funcione de forma similar al siguiente ejemplo: <a href='https://codepen.io/freeCodeCamp/full/mVEJag' target='_blank'>https://codepen.io/freeCodeCamp/full/mVEJag</a>.",
"<strong>Regla #1:</strong> No veas el código del proyecto de ejemplo. Encuentra la forma de hacerlo por tu cuenta.",
"<strong>Regla #2:</strong> Satisface las siguientes <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>historias de usuario</a>. Usa cualquier librería o API que sea necesaria. ¡Ponle un toque personal!.",
"<strong>Regla #3:</strong> Debes utilizar D3.js para construir este proyecto.",
"<strong>Historia de usuario:</strong> Puedo ver a dónde cayeron todos los meteoritos en un mapa mundi.",
"<strong>Historia de usuario:</strong> Puedo distinguir el tamaño relativo de cada meteorito simplemente viendo la forma en que está representado en el mapa.",
"<strong>Historia de usuario:</strong> Puedo mover el ratón sobre el dato de cada meteorito para obtener información adicional.",
"<strong>Pista:</strong> Puedes utilizar el siguiente conjunto de datos para construir tu proyecto: <a href='https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json' target='_blank'>https://raw.githubusercontent.com/freeCodeCamp/ProjectReferenceData/master/meteorite-strike-data.json</a>",
"Recuerda utilizar <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> si te sientes atascado.",
"Cuando termines, haz clic en el botón de \"I've completed this challenge\" e incluye el vínculo de tu proyecto en CodePen. ",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c443eddfaeb5bd0f",
"title": "Manage a Book Trading Club",
"description": [
"<strong>Objective:</strong> Build a <a href='https://glitch.com' target='_blank'>Glitch</a> app that is functionally similar to this: <a href='https://chrome-delivery.glitch.me/ /' target='_blank'>https://chrome-delivery.glitch.me</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can view all books posted by every user.",
"<strong>User Story:</strong> I can add a new book.",
"<strong>User Story:</strong> I can update my settings to store my full name, city, and state.",
"<strong>User Story:</strong> I can propose a trade and wait for the other user to accept the trade.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 4,
"translations": {
"es": {
"description": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='http://bookjump.herokuapp.com/' target='_blank'>http://bookjump.herokuapp.com/</a> y despliégalo en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.org/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Puedo ver todos los libros agregados por cada usuario.",
"<strong>Historia de usuario:</strong> Puedo agregar un nuevo libro.",
"<strong>Historia de usuario:</strong> Puedo actualizar mi configuración para que almacene mi nombre completo, ciudad y Estado.",
"<strong>Historia de usuario:</strong> Puedo proponer un intercambio y esperar a que algún otro usuario acepte el trato.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
],
"title": "Administra un club de intercambio de libros"
}
}
},
{
"id": "bd7158d8c443eddfaeb5bdee",
"title": "Build a Pinterest Clone",
"description": [
"<strong>Objective:</strong> Build a <a href='https://glitch.com' target='_blank'>Glitch</a> app that is functionally similar to this: <a href='https://wild-song.glitch.me/' target='_blank'>https://wild-song.glitch.me</a>.",
"Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> As an unauthenticated user, I can login with GitHub.",
"<strong>User Story:</strong> As an authenticated user, I can link to images.",
"<strong>User Story:</strong> As an authenticated user, I can delete images that I've linked to.",
"<strong>User Story:</strong> As an authenticated user, I can see a Pinterest-style wall of all the images I've linked to.",
"<strong>User Story:</strong> As an unauthenticated user, I can browse other users' walls of images.",
"<strong>User Story:</strong> As an authenticated user, if I upload an image that is broken, it will be replaced by a placeholder image. (can use jQuery broken image detection)",
"<strong>Hint:</strong> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> is a library that allows for Pinterest-style image grids.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 4,
"translations": {
"es": {
"description": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='https://midnight-dust.glitch.me/' target='_blank'>https://midnight-dust.glitch.me/</a> y despliégalo en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.org/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo acceder a mi cuenta con Twitter.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo agregar enlaces a imágenes.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo elimiar imágenes que he agregado.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, puedo ver un muro al estilo de Pinterest con todas las imágenes para las que he agregado un enlace.",
"<strong>Historia de usuario:</strong> Como usuario no autenticado, puedo navegar los muros de imágenes de otros usuarios.",
"<strong>Historia de usuario:</strong> Como usuario autenticado, si agrego una imagen corrupta, será reemplazada por una imagen predeterminada. (Puedes utilizar la detección de imágenes corruptas de jQuery)",
"<strong>Pista:</strong> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> es una librería que permite crear cuadrículas de imágenes al estilo de Pinterest.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
],
"title": "Crea un clon de Pinterest"
}
}
},
{
"id": "bd7158d8c443eddfaeb5bdff",
"title": "Build a Nightlife Coordination App",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that is functionally similar to this: <a href='http://whatsgoinontonight.herokuapp.com/' target='_blank'>http://whatsgoinontonight.herokuapp.com/</a> and deploy it to Heroku.",
"Note that for each project, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> As an unauthenticated user, I can view all bars in my area.",
"<strong>User Story:</strong> As an authenticated user, I can add myself to a bar to indicate I am going there tonight.",
"<strong>User Story:</strong> As an authenticated user, I can remove myself from a bar if I no longer want to go there.",
"<strong>User Story:</strong> As an unauthenticated user, when I login I should not have to search again.",
"<strong>Hint:</strong> Try using the <a href='https://www.yelp.com/developers/documentation/v2/overview' target='_blank'>Yelp API</a> to find venues in the cities your users search for. If you use Yelp's API, be sure to mention so in your app.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 4,
"isRequired": true,
"translations": {
"es": {
"description": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='http://whatsgoinontonight.herokuapp.com/' target='_blank'>http://whatsgoinontonight.herokuapp.com/</a> y despliégala en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Como un usuario no autenticado, puedo ver todos los bares en mi área.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo agregarme a mí mismo a un bar para indicar que voy a estar allí esta noche.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo removerme de un bar si ya no pienso ir allí.",
"<strong>Historia de usuario:</strong> Como un usuario no autenticado, cuando accedo a mi cuenta no debo tener la necesidad de buscar de nuevo.",
"<span class='text-info'>Pista:</span> Prueba utilizar el <a href='https://www.yelp.com/developers/documentation/v2/overview' target='_blank'>API de Yelp</a> para encontrar lugares en las ciudades donde tus usuarios buscan. Si utilizas el API de Yelp, asegúrate de mencionarlo en tu aplicación.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c443eddfaeb5bd0e",
"title": "Chart the Stock Market",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that is functionally similar to this: <a href='http://watchstocks.herokuapp.com/' target='_blank'>http://watchstocks.herokuapp.com/</a> and deploy it to Heroku.",
"Note that for each project, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> I can view a graph displaying the recent trend lines for each added stock.",
"<strong>User Story:</strong> I can add new stocks by their symbol name.",
"<strong>User Story:</strong> I can remove stocks.",
"<strong>User Story:</strong> I can see changes in real-time when any other user adds or removes a stock. For this you will need to use Web Sockets.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 4,
"isRequired": true,
"translations": {
"es": {
"description": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='http://watchstocks.herokuapp.com/' target='_blank'>http://watchstocks.herokuapp.com/</a> y despliégalo en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este Basejump:",
"<strong>Historia de usuario:</strong> Como usuario, puedo ver un gráfico que me muestre las líneas de tendencia recientes para cada acción agregada.",
"<strong>Historia de usuario:</strong> Como usuario, puedo agregar nuevas acciones por su símbolo.",
"<strong>Historia de usuario:</strong> Como usuario, puedo remover acciones.",
"<strong>Historia de usuario:</strong> Como usuario, puedo ver cambios en tiempo real cuando algún otro usuario agrega o remueve una acción. Puedes usar Web Sockets para hacer esto.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "bd7158d8c443eddfaeb5bdef",
"title": "Build a Voting App",
"description": [
"<strong>Objective:</strong> Build a full stack JavaScript app that is functionally similar to this: <a href='https://fcc-voting-arthow4n.herokuapp.com/' target='_blank'>https://fcc-voting-arthow4n.herokuapp.com/</a> and deploy it to Heroku.",
"Note that for each project, you should create a new GitHub repository and a new Heroku project. If you can't remember how to do this, revisit <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Here are the specific user stories you should implement for this project:",
"<strong>User Story:</strong> As an authenticated user, I can keep my polls and come back later to access them.",
"<strong>User Story:</strong> As an authenticated user, I can share my polls with my friends.",
"<strong>User Story:</strong> As an authenticated user, I can see the aggregate results of my polls.",
"<strong>User Story:</strong> As an authenticated user, I can delete polls that I decide I don't want anymore.",
"<strong>User Story:</strong> As an authenticated user, I can create a poll with any number of possible items.",
"<strong>User Story:</strong> As an unauthenticated or authenticated user, I can see and vote on everyone's polls.",
"<strong>User Story:</strong> As an unauthenticated or authenticated user, I can see the results of polls in chart form. (This could be implemented using Chart.js or Google Charts.)",
"<strong>User Story:</strong> As an authenticated user, if I don't like the options on a poll, I can create a new option.",
"Once you've finished implementing these user stories, click the \"I've completed this challenge\" button and enter the URLs for both your GitHub repository and your live app running on Heroku.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],"tests": [],
"challengeType": 4,
"isRequired": true,
"translations": {
"es": {
"description": [
"<strong>Objetivo:</strong> Construye una aplicación de pila completa (full stack) en JavaScript que funcione de forma similar al siguiente proyecto: <a href='https://fcc-voting-arthow4n.herokuapp.com/' target='_blank'>https://fcc-voting-arthow4n.herokuapp.com/</a> y despliégala en Heroku.",
"Ten en cuenta que para cada proyecto, debes crear un nuevo repositorio en GitHub y un nuevo proyecto en Heroku. Si no recuerdas cómo hacerlo, visita de nuevo <a href='/challenges/get-set-for-our-dynamic-web-application-projects'>https://freecodecamp.com/challenges/get-set-for-our-dynamic-web-application-projects</a>.",
"Estas son las Historias de usuario que debes satisfacer para este proyecto:",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo guardar mis votaciones y acceder a ellas posteriormente.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo compartir mis votaciones con mis amigos.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo ver los resultados agregados de mis votaciones.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo eliminar votaciones que ya no quiero tener guardadas.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, puedo crear una votación con cualquier número de opciones.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado o no autenticado, puedo ver y votar en las votaciones de otros.",
"<strong>Historia de usuario:</strong> Como un usuario autenticado o no autenticado, puedo ver los resultados de las votaciones por medio de un gráfico. (Esto podría implementarse utilizando Chart.js o Google Charts.)",
"<strong>Historia de usuario:</strong> Como un usuario autenticado, si no me gustan las opciones en una votación, puedo crear una nueva opción.",
"Una vez hayas terminado de implementar estas historias de usuario, pulsa el botón de \"I've completed this challenge\" e incluye las URLs de tu repositorio GitHub y de tu aplicación corriendo en Heroku.",
"Puedes obtener retroalimentación acerca de tu proyecto de parte de tus compañeros campistas compartiéndolo en nuestro <a href='//gitter.im/freecodecamp/codereview' target='_blank'>Cuarto de revisión de código</a>. También puedes compartirlo en Twitter y en el campamento de tu ciudad (en Facebook)."
]
}
}
},
{
"id": "5a4b7fcdb66f799f199e11db",
"title": "Build a Pong Game",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/satyamdev/full/pdMmBp' target='_blank'>https://codepen.io/satyamdev/full/pdMmBp</a>.",
"<strong>Rule #1:</strong> Don't look at the example project's code. Figure it out for yourself.",
"<strong>Rule #2:</strong> Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can control a paddle.",
"<strong>User Story:</strong> The computer can control the other paddle.",
"<strong>User Story:</strong> The computer's paddle is unbeatable. It should never miss the ball.",
"<strong>User Story:</strong> The game keeps track of the player and computer's score.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false
},
{
"id": "5a5d02bd919fcf9ca8cf46cb",
"title": "Build a Light-Bright App",
"description": [
"<strong>Objective:</strong> Build a <a href='https://codepen.io' target='_blank'>CodePen.io</a> app that is functionally similar to this: <a href='https://codepen.io/freeCodeCamp/full/eyLYXE' target='_blank'>https://codepen.io/freeCodeCamp/full/eyLYXE</a>.",
"<strong>Rule #1:</strong> Don't look at the example project's code. Figure it out for yourself.",
"<strong>Rule #2:</strong> Fulfill the below <a href='https://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a>. Use whichever libraries or APIs you need. Give it your own personal style.",
"<strong>User Story:</strong> I can click or drag the mouse cursor to color the circles.",
"<strong>User Story:</strong> I can double-click on a colored circle to remove the color.",
"<strong>User Story:</strong> I can click on a colored circle to change its color.",
"<strong>User Story:</strong> I should get a circle of different color on each click.",
"<strong>User Story:</strong> I can click on the 'Reset' button to remove the recent color.",
"<strong>User Story:</strong> I can click on the 'Reset All' button to remove all the colors from the circles.",
"Remember to use <a href='http://forum.freecodecamp.org/t/how-to-get-help-when-you-are-stuck/19514' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"When you are finished, click the \"I've completed this challenge\" button and include a link to your CodePen.",
"You can get feedback on your project by sharing it with your friends on Facebook."
],
"tests": [],
"challengeType": 3,
"isRequired": false
}
],
"fileName": "08-coding-interview-questions-and-take-home-assignments/take-home-interview-projects.json",
"superBlock": "coding-interview-questions-and-take-home-assignments",
"superOrder": 8
}

View File

@ -0,0 +1,36 @@
{
"name": "API's and Microservices Certificate",
"order": 5,
"isPrivate": true,
"challenges": [
{
"id": "561add10cb82ac38a17523bc",
"title": "API's and Microservices Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7158d8c443edefaeb5bdef",
"title": "Timestamp Microservice"
},
{
"id": "bd7158d8c443edefaeb5bdff",
"title": "Request Header Parser Microservice"
},
{
"id": "bd7158d8c443edefaeb5bd0e",
"title": "URL Shortener Microservice"
},
{
"id": "5a8b073d06fa14fcfde687aa",
"title": "Exercise Tracker"
},
{
"id": "bd7158d8c443edefaeb5bd0f",
"title": "File Metadata Microservice"
}
]
}
]
}

View File

@ -0,0 +1,36 @@
{
"name": "Data Visualization Certificate",
"order": 4,
"isPrivate": true,
"challenges": [
{
"id": "5a553ca864b52e1d8bceea14",
"title": "Data Visualization Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7168d8c242eddfaeb5bd13",
"title": "Visualize Data with a Bar Chart"
},
{
"id": "bd7178d8c242eddfaeb5bd13",
"title": "Visualize Data with a Scatterplot Graph"
},
{
"id": "bd7188d8c242eddfaeb5bd13",
"title": "Visualize Data with a Heat Map"
},
{
"id": "587d7fa6367417b2b2512bbf",
"title": "Visualize Data with a Choropleth Map"
},
{
"id": "587d7fa6367417b2b2512bc0",
"title": "Visualize Data with a Treemap Diagram"
}
]
}
]
}

View File

@ -0,0 +1,36 @@
{
"name": "Front End Libraries Certificate",
"order": 3,
"isPrivate": true,
"challenges": [
{
"id": "561acd10cb82ac38a17513bc",
"title": "Front End Libraries Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine"
},
{
"id": "bd7157d8c242eddfaeb5bd13",
"title": "Build a Markdown Previewer"
},
{
"id": "587d7dbc367417b2b2512bae",
"title": "Build a Drum Machine"
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator"
},
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock"
}
]
}
]
}

View File

@ -0,0 +1,36 @@
{
"name": "Information, Securtiy and Quality Assurance Certificate",
"order": 6,
"isPrivate": true,
"challenges": [
{
"id": "561add10cb82ac38a17213bc",
"title": "Information, Securtiy and Quality Assurance Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "587d8249367417b2b2512c42",
"title": "Issue Tracker"
},
{
"id": "587d8249367417b2b2512c41",
"title": "Metric-Imperial Converter"
},
{
"id": "587d824a367417b2b2512c43",
"title": "Personal Library"
},
{
"id": "587d824a367417b2b2512c44",
"title": "Stock Price Checker"
},
{
"id": "587d824a367417b2b2512c45",
"title": "Anonymous Message Board"
}
]
}
]
}

View File

@ -0,0 +1,36 @@
{
"name": "JavaScript Algorithms and Data Structures Certificate",
"order": 2,
"isPrivate": true,
"challenges": [
{
"id": "561abd10cb81ac38a17513bc",
"title": "JavaScript Algorithms and Data Structures Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Palindrome Checker"
},
{
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter"
},
{
"id": "56533eb9ac21ba0edf2244e2",
"title": "Caesars Cipher"
},
{
"id": "aff0395860f5d3034dc0bfc9",
"title": "Telephone Number Validator"
},
{
"id": "aa2e6f85cab2ab736c9a9b24",
"title": "Cash Register"
}
]
}
]
}

View File

@ -0,0 +1,56 @@
{
"name": "Legacy Back End Certificate",
"order": 1,
"isPrivate": true,
"challenges": [
{
"id": "660add10cb82ac38a17513be",
"title": "Legacy Back End Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7158d8c443edefaeb5bdef",
"title": "Timestamp Microservice"
},
{
"id": "bd7158d8c443edefaeb5bdff",
"title": "Request Header Parser Microservice"
},
{
"id": "bd7158d8c443edefaeb5bd0e",
"title": "URL Shortener Microservice"
},
{
"id": "bd7158d8c443edefaeb5bdee",
"title": "Image Search Abstraction Layer"
},
{
"id": "bd7158d8c443edefaeb5bd0f",
"title": "File Metadata Microservice"
},
{
"id": "bd7158d8c443eddfaeb5bdef",
"title": "Build a Voting App"
},
{
"id": "bd7158d8c443eddfaeb5bdff",
"title": "Build a Nightlife Coordination App"
},
{
"id": "bd7158d8c443eddfaeb5bd0e",
"title": "Chart the Stock Market"
},
{
"id": "bd7158d8c443eddfaeb5bd0f",
"title": "Manage a Book Trading Club"
},
{
"id": "bd7158d8c443eddfaeb5bdee",
"title": "Build a Pinterest Clone"
}
]
}
]
}

View File

@ -0,0 +1,56 @@
{
"name": "Legacy Data Visualization Certificate",
"order": 1,
"isPrivate": true,
"challenges": [
{
"id": "561add10cb82ac39a17513bc",
"title": "Legacy Data Visualization Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7157d8c242eddfaeb5bd13",
"title": "Build a Markdown Previewer"
},
{
"id": "bd7156d8c242eddfaeb5bd13",
"title": "Build a Camper Leaderboard"
},
{
"id": "bd7155d8c242eddfaeb5bd13",
"title": "Build a Recipe Box"
},
{
"id": "bd7154d8c242eddfaeb5bd13",
"title": "Build the Game of Life"
},
{
"id": "bd7153d8c242eddfaeb5bd13",
"title": "Build a Roguelike Dungeon Crawler Game"
},
{
"id": "bd7168d8c242eddfaeb5bd13",
"title": "Visualize Data with a Bar Chart"
},
{
"id": "bd7178d8c242eddfaeb5bd13",
"title": "Visualize Data with a Scatterplot Graph"
},
{
"id": "bd7188d8c242eddfaeb5bd13",
"title": "Visualize Data with a Heat Map"
},
{
"id": "bd7198d8c242eddfaeb5bd13",
"title": "Show National Contiguity with a Force Directed Graph"
},
{
"id": "bd7108d8c242eddfaeb5bd13",
"title": "Map Data Across the Globe"
}
]
}
]
}

View File

@ -0,0 +1,56 @@
{
"name": "Legacy Front End Certificate",
"order": 1,
"isPrivate": true,
"challenges": [
{
"id": "561add10cb82ac38a17513be",
"title": "Legacy Front End Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7158d8c242eddfaeb5bd13",
"title": "Build a Personal Portfolio Webpage"
},
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine"
},
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock"
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator"
},
{
"id": "bd7158d8c442eddfaeb5bd10",
"title": "Show the Local Weather"
},
{
"id": "bd7158d8c442eddfaeb5bd1f",
"title": "Use the Twitch JSON API"
},
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Stylize Stories on Camper News"
},
{
"id": "bd7158d8c442eddfaeb5bd19",
"title": "Build a Wikipedia Viewer"
},
{
"id": "bd7158d8c442eedfaeb5bd1c",
"title": "Build a Tic Tac Toe Game"
},
{
"id": "bd7158d8c442eddfaeb5bd1c",
"title": "Build a Simon Game"
}
]
}
]
}

View File

@ -0,0 +1,36 @@
{
"name": "Responsive Web Design Certificate",
"order": 1,
"isPrivate": true,
"challenges": [
{
"id": "561add10cb82ac38a17513bc",
"title": "Responsive Web Design Certificate",
"challengeType": 7,
"description": [],
"isPrivate": true,
"tests": [
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Build a Tribute Page"
},
{
"id": "587d78af367417b2b2512b03",
"title": "Build a Survey Form"
},
{
"id": "587d78af367417b2b2512b04",
"title": "Build a Product Landing Page"
},
{
"id": "587d78b0367417b2b2512b05",
"title": "Build a Technical Documentation Page"
},
{
"id": "bd7158d8c242eddfaeb5bd13",
"title": "Build a Personal Portfolio Webpage"
}
]
}
]
}

View File

@ -0,0 +1,42 @@
/* eslint-env node */
const types = [
{
value: 'feat',
name: 'feat: A new challenge or feature is being added.'
},
{
value: 'fix',
name: `fix: Modifying an existing challenge, fixing a bug, text,
or updating challenge tests.`
},
{
value: 'docs',
name: 'docs: Documentation only changes to readme, guides, etc.'
},
{
value: 'test',
name: `test: Adding missing tests to tooling (NOT to be used for tests
inside challenges).`
},
{
value: 'chore',
name: `chore: Changes to the build process or auxiliary tools
and libraries such as documentation generation.`
},
{
value: 'revert',
name: 'revert: Revert a commit.'
}
];
const scopes = ['challenges', 'tools', 'scripts'].map(name => ({
name
}));
module.exports = {
types,
scopes,
allowCustomScopes: true,
allowBreakingChanges: ['feat', 'fix', 'perf', 'refactor']
};

View File

@ -0,0 +1,24 @@
/* eslint-env node */
const { types, scopes, allowCustomScopes } = require('./commitizen.config');
const validTypes = types.map(type => type.value);
const validScopes = scopes.map(scope => scope.name);
const scopeValidationLevel = allowCustomScopes ? 0 : 2;
module.exports = {
extends: ['@commitlint/config-conventional'],
// Add your own rules. See http://marionebl.github.io/commitlint
rules: {
// Apply valid scopes and types
'scope-enum': [scopeValidationLevel, 'always', validScopes],
'type-enum': [2, 'always', validTypes],
// Disable subject-case rule
'subject-case': [0, 'always'],
// Disable language rule
lang: [0, 'always', 'eng']
}
};

View File

@ -0,0 +1,6 @@
var fs = require('fs');
var getChallenges = require('./getChallenges');
var challengeSpecs = getChallenges();
fs.writeFileSync('seed/challenge-bundle.json', JSON.stringify(challengeSpecs));

View File

@ -0,0 +1,445 @@
# Contributor's Guide
We welcome pull requests from freeCodeCamp campers (our students) and seasoned JavaScript developers alike! Follow these steps to contribute:
1. Find an issue that needs assistance by searching for the [Help Wanted](https://github.com/freeCodeCamp/curriculum/labels/help%20wanted) tag.
2. Let us know you are working on it by posting a comment on the issue.
3. Follow the instructions in this guide to start working on the issue.
Working on your first Pull Request? You can learn how from this *free* series [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
### Need Help?
freeCodeCamp Issue Mods and staff are on hand to assist with any contributing related issues in our [Contributors chat room](https://gitter.im/FreeCodeCamp/Contributors).
### Found a bug?
If you think you've found a bug, first read the [Help I've Found a Bug](https://forum.freecodecamp.org/t/how-to-report-a-bug/19543) article and follow its instructions. If you're confident it's a new bug, go ahead and create a new GitHub issue. Be sure to include as much information as possible so we can reproduce the bug.
## Quick Reference
|command|description|
|---|---|
| `npm run test` | run all JS tests in the system, including client, server, lint, and challenge tests |
| `npm run test-challenges` | run all challenge tests (for each challenge JSON file, run all `tests` against all `solutions`) |
| `npm run commit` | interactive tool to help you build a good commit message |
| `npm run unpack` | extract challenges from `seed/challenges` into `unpacked` subdirectory, one HTML page per challenge - see [Unpack and Repack](#unpack-and-repack) |
| `npm run repack` | repack challenges from `unpacked` subdirectory into `seed/challenges` |
## Table of Contents
**[Setup](#setup-guide)**
- [Prerequisites](#prerequisites)
- [Fork the Project](#fork-the-project)
- [Set Up Linting](#set-up-linting)
- [Set Up Curriculum](#set-up-curriculum)
**[Make Changes](#make-changes)**
- [About the Challenges](#about-the-challenges)
- [Find Code to Change](#find-code-to-change)
- [Maintain Your Fork](#maintain-your-fork)
- [Create a Branch](#create-a-branch)
- [Modify the Code](#modify-the-code)
- [Run The Test Suite](#run-the-test-suite)
- [Stage Your Changes](#stage-your-changes)
- [Commit Your Changes](#commit-your-changes)
**[Submit](#submit)**
- [Create a Pull Request](#create-a-pull-request)
- [Common Steps](#common-steps)
- [How We Review and Merge Pull Requests](#how-we-review-and-merge-pull-requests)
- [How We Close Stale Issues](#how-we-close-stale-issues)
- [Next Steps](#next-steps)
**[Other Resources](#other-resources)**
- [Unpack and Repack](#unpack-and-repack)
- [Challenge Template](#challenge-template)
- [Useful Links](#useful-links)
--------------------------------------------------------------------------------
## Setup
### Prerequisites
| Prerequisite | Version |
| ------------------------------------------- | ------- |
| [Node.js](http://nodejs.org) | `~ ^8.9.3` |
| npm (comes with Node) | `~ ^5` |
| [MongoDB Community Server](https://docs.mongodb.com/manual/administration/install-community/) | `~ ^3` |
**Note**: MongoDB is optional. Its only necessary if you need to generate a unique ObjectId, such as when youre creating a new challenge or project to add to the curriculum.
If Node.js is already installed on your machine, run the following commands to validate the versions of Node and npm:
```shell
node -v
npm -v
```
To check your version of MongoDB, run:
```shell
mongo --version
```
To check your MongoDB version on Windows, you'll have to locate the installation directory. It is probably located at `C:\Program Files\MongoDB\Server\3.4\`, where 3.4 is your version number.
If your versions are lower than the prerequisite versions, you should update.
> _Updating to the latest releases is recommended_.
### Fork the Project
#### Setting Up Your System
1. Install [Git](https://git-scm.com/) or your favorite Git client.
2. (Optional) [Setup an SSH Key](https://help.github.com/articles/generating-an-ssh-key/) for GitHub.
#### Forking freeCodeCamp Curriculum
1. Go to the top level freeCodeCamp Curriculum repository: <https://github.com/freeCodeCamp/curriculum>
2. Click the "Fork" Button in the upper right hand corner of the interface ([more details here](https://help.github.com/articles/fork-a-repo/)).
3. After the repository (repo) has been forked, you will be taken to your copy of the freeCodeCamp repo at <https://github.com/yourUsername/curriculum>.
#### Cloning Your Fork
1. Open a terminal / command line / bash shell in your projects directory:
```shell
/yourprojectdirectory/
```
2. Clone your fork of freeCodeCamp:
```shell
$ git clone https://github.com/yourUsername/curriculum.git
```
> Make sure to replace `yourUsername` with your GitHub username.
This will download the entire freeCodeCamp Curriculum repo from your fork to your projects directory.
#### Set Up Your Upstream
1. Change directory to the newly created `curriculum` directory:
```shell
$ cd curriculum
```
2. Add a remote to the official freeCodeCamp Curriculum repo:
```shell
$ git remote add upstream https://github.com/freeCodeCamp/curriculum.git
```
Congratulations, you now have a local copy of the freeCodeCamp Curriculum repo!
### Set Up Linting
You should have [ESLint running in your editor](http://eslint.org/docs/user-guide/integrations.html), and it will highlight anything doesn't conform to [freeCodeCamp's JavaScript Style Guide](http://forum.freecodecamp.org/t/free-code-camp-javascript-style-guide/19121) (you can find a summary of those rules [here](https://github.com/freeCodeCamp/freeCodeCamp/blob/staging/.eslintrc)).
> Please do not ignore any linting errors, as they are meant to **help** you and to ensure a clean and simple code base.
### Set Up Curriculum
Once you have freeCodeCamp Curriculum cloned, you first need to install all of the dependencies:
```bash
# Install NPM dependencies
$ npm install
```
If that doesnt work, let us know by asking in the [Contributors chat room](https://gitter.im/FreeCodeCamp/Contributors) on Gitter. There might be an error in the console of your browser or in the terminal / command line / bash shell that will help identify the problem.
## Make Changes
### About the Challenges
The challenges are stored inside the `challenges` directory (and its various subdirectories).
The `challenge` directory contains all the challenges that appear on the freeCodeCamp Learn platform.
For each challenge section, there is a JSON file (fields documented below) containing its name, seed HTML, tests, and so on.
For more about creating challenges, see the [Challenge Style Guide](./challenge-style-guide.md).
### Find Code to Change
The best way to find out any code you wish to change, add, or remove is using the GitHub search bar at the top of the [freeCodeCamp Curriculum](https://github.com/freeCodeCamp/curriculum) repository page. For example, you could search for a challenge name and the results will display the JSON file with that challenge, along with line numbers. Then you can proceed to the file locally, find the challenge, and your make changes.
Always feel free to reach out to the chat room when you are not certain of anything specific in the code.
### Maintain Your Fork
Now that you have a copy of your fork, there is work you will need to do to keep it current. Before creating a new branch for a [pull request](#what-is-a-pull-request):
1. Make sure you are on the `dev` branch:
```shell
$ git status
On branch dev
Your branch is up-to-date with 'origin/dev'.
```
If your aren't on `dev`, resolve outstanding files / commits and checkout the `dev` branch
```shell
$ git checkout dev
```
2. Do a pull with rebase against `upstream`:
```shell
$ git pull --rebase upstream dev
```
This will pull down all of the changes made to the official freeCodeCamp Curriculum `dev` branch, without making an additional commit in your local repo.
3. (_Optional_) Force push your updated staging branch to your GitHub fork:
```shell
$ git push origin dev --force
```
This will overwrite the dev branch of your fork.
### Create a Branch
Once your local copy of the curriculum is up to date, you will need to create a separate branch specific to the issue / feature you're working on. You will push your work to this branch.
> IMPORTANT: ALWAYS EDIT ON A BRANCH
>
> Take away only one thing from this document: Never, **EVER**
make edits to the `dev` branch. ALWAYS make a new branch BEFORE you edit files. This is critical, because if your PR is not accepted, your copy of `dev` will be forever sullied and the only easy way to fix it is to delete your fork and re-fork.
#### Naming Your Branch
Name the branch something like `fix/xxx` or `feature/xxx`, where `xxx` is a short description of the changes or feature you are attempting to add. For example, `fix/typo-es6-challenge` would be a branch where you correct a spelling error in one of the ES6 challenges.
#### Adding Your Branch
To create a branch on your local machine (and switch to this branch):
```shell
$ git checkout -b [name_of_your_new_branch]
```
And to push it to GitHub:
```shell
$ git push origin [name_of_your_new_branch]
```
> If you need more help with branching, take a look at this [cheat sheet](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches).
### Modify the Code
Edit your file(s) locally with the editor of your choice. See the [challenge template](#challenge-template) for more information about the properties of each challenge object.
For an alternate method of editing files locally, you may want to use `unpack` and `repack` -- see [Unpack and Repack](#unpack-and-repack) for instructions.
### Run The Test Suite
When you're finished making changes, run the test suite:
```shell
$ npm run test
```
If some tests don't pass, check your terminal / command line / bash shell for errors and make the required changes.
### Stage Your Changes
Check your `git status` to see unstaged files:
```bash
$ git status
On branch fix/typo-es6-challenge
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: challenges/02-javascript-algorithms-and-data-structures/es6.json
no changes added to commit (use "git add" and/or "git commit -a")
```
To add your edited files, run:
```shell
$ git add path/to/filename.ext
```
You can also run `git add .` to add all unstaged files. Take care, though, because you can accidentally add files you don't want added. Review your `git status` first.
### Commit Your Changes
We have a [tool](https://commitizen.github.io/cz-cli/) that helps you make standard commit messages. Execute `npm run commit` and follow the steps. This will generate a conventional commit message.
**Note**: Your pull request will fail the Travis CI build if your commits do not have conventional messages. [Click here](https://conventionalcommits.org/#why-use-conventional-commits) to read more about conventional commit messages.
If you want to add/remove changes to previous commit, [add the files](#making-your-changes), and use `git commit --amend` or `git commit --amend --no-edit` (to keep the same commit message).
[Squash your commits](http://forum.freecodecamp.org/t/how-to-squash-multiple-commits-into-one-with-git/13231) if there are more than one.
#### Push Your Changes
To push your commit to your GitHub fork:
```bash
$ git push origin branch/name-here
```
## Submit
### Create a Pull Request
#### What is a Pull Request?
A pull request (PR) is a method of submitting proposed changes to the freeCodeCamp Curriculum repo (or any repo, for that matter). You will make changes to copies of the files which make up Curriculum in a personal fork, then apply to have them accepted by the freeCodeCamp/Curriculum proper.
### Common Steps
1. Once the edits have been committed, you will be prompted to create a pull request on your fork's GitHub Page.
2. By default, all pull requests should be against the freeCodeCamp Curriculum repos `dev` branch.
**Make sure that your Base Fork is set to freeCodeCamp/curriculum when raising a pull request.**
![pr-fork-instructions](images/pr-fork-instructions.png)
3. Submit a [pull request](http://forum.freecodecamp.org/t/how-to-contribute-via-a-pull-request/19368) from your branch to the freeCodeCamp Curriculum `dev` branch.
4. In the body of your PR include a more detailed summary of the changes you made and why.
- If the PR is meant to fix an existing bug/issue then, at the end of your PR's description, append the keyword `Closes` and #xxxx (where xxxx is the issue number). Example: `Closes #1337`. This tells GitHub to close the existing issue, if the PR is merged.
5. Indicate if you have tested on a local copy of the site or not.
### How We Review and Merge Pull Requests
freeCodeCamp has a team of volunteer Issue Moderators. These Issue Moderators routinely go through open pull requests in a process called [Quality Assurance](https://en.wikipedia.org/wiki/Quality_assurance) (QA).
1. If an Issue Moderator QA's a pull request and confirms that the new code does what it is supposed without seeming to introduce any new bugs, they will comment "LGTM" which means "Looks good to me."
2. Another Issue Moderator will QA the same pull request. Once they have also confirmed that the new code does what it is supposed to without seeming to introduce any new bugs, they will merge the pull request.
If you would like to apply to join our Issue Moderator team, message [@quincylarson](https://gitter.im/quincylarson) with links to 5 of your pull requests that have been accepted and 5 issues where you have helped someone else through commenting or QA'ing.
### How We Close Stale Issues
We will close any issues or pull requests that have been inactive for more than 15 days, except those that match the following criteria:
- bugs that are confirmed
- pull requests that are waiting on other pull requests to be merged
- features that are a part of a GitHub project
### Next Steps
#### If your PR is accepted
Once your PR is accepted, you may delete the branch you created to submit it. This keeps your working fork clean.
You can do this with a press of a button on the GitHub PR interface. You can delete the local copy of the branch with: `git branch -D branch/to-delete-name`
#### If your PR is rejected
Don't despair! You should receive solid feedback from the Issue Moderators as to why it was rejected and what changes are needed.
Many Pull Requests, especially first Pull Requests, require correction or updating. You can make the requested changes to your local copy and amend your commit with: `git commit --amend`. This will let you update your existing commit. When you push it to your fork you will need to do a force push to overwrite your old commit: `git push --force`
Be sure to post in the PR conversation that you have made the requested changes.
## Other Resources
### Unpack and Repack
`npm run unpack` extracts challenges into separate HTML files under `challenges/unpacked` for easier viewing and editing. The files are `.gitignore`d and will *not* be checked in, and is essentially a tool for editing the `challenge.json` files in the browser.
These unpacked files are self-contained and run their own tests -- open a browser JS console to see the test results.
> **Note**: These in-browser tests should work for simple JavaScript challenges. But other types of challenges may not fare so well. For HTML challenges, challenge tests assume that the solution HTML is the only HTML on the whole page, so jQuery selectors may select seed *and* solution elements. For React / Modern JS challenges, we would need to transpile JSX or ES6 before running the tests.
`npm run repack` gathers up the unpacked/edited HTML files into challenge-block JSON files. After running repack, use `git diff` to see the changes in your console.
When editing the unpacked files, you must only insert or edit lines between comment fences like `<!--description-->` and `<!--end-->`. In descriptions, you can insert a paragraph break with `<!--break-->`.
Unpacked lines that begin with `//--JSON:` are parsed and inserted verbatim.
If you want to **add a challenge**, **change the order** of challenges in a block, or **edit the title** or any other fields of a challenge, you must do that work *inside the main seed JSON file* and then re-run `unpack`.
### Challenge Template
```
{
"id": "Unique identifier (alphanumerical, MongoDB _id)",
"title": "Challenge Title",
"description": [
"A Description of the challenge and what is required to pass",
"A new string in the array will create a new paragraph."
],
"tests": [
{
"text": "Should return \"foo\".",
"testString": "A stringified function using Chai asserts"
}
],
"challengeType": 1,
"translations": {
"language-code": {
"title": "The Title in a Different Language",
"description": [
"The description in a different language."
]
}
},
"files": {
"indexjs": {
"key": "indexjs",
"ext": "js",
"name": "index",
"contents": [
"// code displayed in the editor by default",
"// a new string in the array is a new line"
],
"head": [
"A place for test setup",
"Can be thought of as mocha's beforeEach()"
],
"tail": [
"A place for test tear down",
"Can be thought of as mocha's afterEach()"
]
}
}
},
```
### Useful Links
* Creating and Editing Challenges:
- [Challenge Style Guide](challenge-style-guide.md) - how to create and format challenges
- [Challenge types](https://github.com/freeCodeCamp/learn/blob/a5cb25704168aa37f59a582f0bb5a19b7bd89b46/utils/challengeTypes.js) - what the numeric challenge type values mean (enum).
- [Contributing to FreeCodeCamp - Writing ES6 Challenge Tests ](https://www.youtube.com/watch?v=iOdD84OSfAE#t=2h49m55s) - a video following [Ethan Arrowood](https://twitter.com/ArrowoodTech) as he contributes to the curriculum
* Bugs and Issues:
- [Searching for Your Issue on GitHub](http://forum.freecodecamp.org/t/searching-for-existing-issues/19139)
- [Creating a New GitHub Issue](http://forum.freecodecamp.org/t/creating-a-new-github-issue/18392)
- [Select Issues for Contributing Using Labels](http://forum.freecodecamp.org/t/free-code-camp-issue-labels/19556)
* Miscellaneous:
- [How to clone the freeCodeCamp website on a Windows PC](http://forum.freecodecamp.org/t/how-to-clone-and-setup-the-free-code-camp-website-on-a-windows-pc/19366)
- [How to log in to your local freeCodeCamp site using GitHub](http://forum.freecodecamp.org/t/how-to-log-in-to-your-local-instance-of-free-code-camp/19552)
- [Writing great git commit messages](http://forum.freecodecamp.org/t/writing-good-git-commit-messages/13210)
- [Contributor Chat Support](https://gitter.im/FreeCodeCamp/Contributors) - for the freeCodeCamp repositories, and running a local instance

View File

@ -0,0 +1,153 @@
# A guide to designing freeCodeCamp coding challenges
> "Talk is cheap. Show me the code."Linus Torvalds
freeCodeCamp offers 1,200 hours of interactive coding challenges. These are 100% focused on the practical skill of building software. You code the entire time. You learn to code by coding.
You can learn theory through free online university courses. freeCodeCamp will focus instead on helping you learn to code and practice by building apps.
With that practical focus in mind, lets talk about the requirements for our coding challenges. (Note that these requirements do not apply to our algorithm challenges, checkpoint challenges, or projects.)
**Table of Contents**
- [Proper nouns](#proper-nouns)
- [The 2 minute rule](#the-2-minute-rule)
- [Modularity](#modularity)
- [Naming challenges](#naming-challenges)
- [Writing tests](#writing-tests)
- [Writing instructions](#writing-instructions)
- [Formatting challenge text](#formatting-challenge-text)
- [Formatting seed code](#formatting-seed-code)
- [Why do we have all these rules?](#why-do-we-have-all-these-rules)
## Proper nouns
Proper nouns should use correct capitalization when possible. Below is a list of words as they should appear in the challenges.
- JavaScript (capital letters in "J" and "S" and no abbreviations)
- Node.js
Front-end development (adjective form with a dash) is when you're working on the front end (noun form with no dash). The same goes with "back end", "full stack", and many other compound terms.
## The 2 minute rule
Each challenge should be solvable within 120 seconds by a native English speaker who has completed the challenges leading up to it. This includes the amount of time it takes to read the directions, understand the seeded code, write their own code, and get all the tests to pass.
If it takes longer than two minutes to complete the challenge, you have two options:
- simplify the challenge, or
- split the challenge into two challenges.
The 2 minute rule forces you, the challenge designer, to make your directions concise, your seed code clear, and your tests straight-forward.
We have JavaScript events that track how long it takes for campers to solve challenges and we can use them to identify challenges that need to be simplified or split.
## Modularity
Each challenge should teach exactly one concept, and that concept should be apparent from the challenge's name.
We can reinforce previously covered concepts through repetition and variations - for example, introducing h1 elements in one challenge, then h3 elements a few challenges later.
Our goal is to have thousands of 2-minute challenges. These can flow together and reiterate previously-covered concepts.
## Naming challenges
Naming things is hard. We've made it easier by imposing some constraints.
All challenge titles should be explicit and should follow this pattern:
[verb] [object clause]
Here are some example challenge names:
- Use Clockwise Notation to Specify the Padding of an Element
- Condense arrays with .reduce
- Use Bracket Notation to Find the First Character in a String
## Numbering Challenges
Every challenge needs an `id`. If you don't specify one, then MongoDB will create a new random one when it saves the data; however, we don't want it to do that, since we want the challenge ids to be consistent across different environments (staging, production, lots of different developers, etc.).
To generate a new one in a shell (assuming MongoDB is running separately):
1. Run `mongo` command
2. Run `ObjectId()` command
For example:
```sh
$ mongo
MongoDB shell version v3.6.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.10
...
$ ObjectId()
ObjectId("5a474d78df58bafeb3535d34")
```
The result is a new id, for example `5a474d78df58bafeb3535d34` above.
Once you have your id, put it into the JSON file as the `id` field, e.g.
```
{
"id": "5a474d78df58bafeb3535d34",
"title": "Challenge Title",
```
## Writing tests
Challenges should have the minimum number of tests necessary to verify that a camper understands a concept.
Our goal is to communicate the single point that the challenge is trying to teach, and test that they have understood that point.
Challenge tests can make use of the Node.js and Chai.js assertion libraries. Also, if needed, user-generated code can be accessed in the `code` variable.
## Writing instructions
Challenges should be written with short, clear sentences, and use as little jargon as necessary. All jargon should be defined immediately in plain English.
Keep paragraphs short (around 1-4 sentences). People are more likely to read several short paragraphs over a wall of text.
Challenge text should use the second person ("you") to help to give it a conversational tone. This way, the text and instructions seem to speak directly to the camper working through the challenge. Try to avoid using the first person ("I", "we", "let's", and "us").
Don't use outbound links. These interrupt the flow. And campers should never have to google anything during these challenges. If there are resources you think campers would benefit from, add them to the challenge's wiki article on the forum.
You can add diagrams if absolutely necessary.
Don't use emojis or emoticons in challenges. freeCodeCamp has a global community, and the cultural meaning of an emoji or emoticon may be different around the world. Also, emojis can render differently on different systems.
## Formatting challenge text
Here are specific formatting guidelines for challenge text and examples:
- Language keywords go in `<code>` tags. For example, HTML tag names or CSS property names
- The first instance of a keyword when it's being defined, or general keywords (i.e. "object" or "immutable") go in `<dfn>` tags
- Single line code examples go in `<code>` tags
- Multi-line code examples go in `<blockquote>` tags, and use the `<br>` tag to separate lines. For HTML examples, remember to use escape characters to represent the angle brackets
- A single horizontal rules (`<hr>` tag) should separate the text discussing the challenge concept and the challenge instructions
- Additional information in the form of a note should be formatted `<strong>Note</strong><br>Rest of note text...`
- Use double quotes where applicable
## Formatting seed code
Here are specific formatting guidelines for the challenge seed code:
- Use two spaces to indent
- JavaScript statements end with a semicolon
- Use double quotes where applicable
- Comments made should have a space between the comment characters and the comment themselves
`// Fix this line`
## Why do we have all these rules?
Our goal is to have a fun, clear interactive learning experience.
Designing interactive coding challenges is hard. It would be so much easier to write a lengthy explanation, or to create a video tutorial. There's a place for those on Medium and YouTube. But for our core curriculum, we're sticking with what works best for most people - a fully interactive, video game-like experience.
We want campers to achieve a flow state. We want them to build momentum and blast through our curriculum with as few snags as possible. We want them to go into the projects with confidence and a wide exposure to programming concepts.
Creating these challenges requires immense creativity and attention to detail. But you'll have plenty of help. You have support from a whole team of contributors, whom you can bounce ideas off of and demo your challenges to. Stay active in the [contributors room](https://gitter.im/freecodecamp/contributors) and ask lots of questions.
With your help, we can design an interactive coding curriculum that will help millions of people learn to code for years to come.

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,127 @@
{
"name": "Open Source for Good",
"order": 22,
"time": "",
"message": "Once you feel ready, you can get real-world experience by contributing to these open source tools used by nonprofits.",
"challenges": [
{
"title": "Mail for Good",
"id": "5a1879ed19a2ae635c8afa76",
"description": [
[
"",
"",
"Mail for Good is an open source email campaign management tool for nonprofits.",
"https://github.com/freeCodeCamp/mail-for-good"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "Pantry for Good",
"id": "5a1879f119a2ae635c8afa7b",
"description": [
[
"",
"",
"Pantry for Good is an open source food bank logistics and inventory management tool.",
"https://github.com/freeCodeCamp/pantry-for-good"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "Meeting for Good",
"id": "5a1879f019a2ae635c8afa7a",
"description": [
[
"",
"",
"Meeting for Good is an open source meeting coordination app for nonprofit teams.",
"https://github.com/freeCodeCamp/meeting-for-good"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "League for Good",
"id": "5a1879ef19a2ae635c8afa79",
"description": [
[
"",
"",
"League for Good is an open source sports league management tool.",
"https://github.com/freeCodeCamp/league-for-good"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "Conference for Good",
"id": "5a1879ef19a2ae635c8afa78",
"description": [
[
"",
"",
"Conference for Good is an open source conference management tool.",
"https://github.com/freeCodeCamp/conference-for-good"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "The freeCodeCamp Core Platform",
"id": "5a1879ee19a2ae635c8afa77",
"description": [
[
"",
"",
"The freeCodeCamp core platform is the learning resource you are using right now at this exact moment ;)",
"https://github.com/freecodecamp/freecodecamp"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
},
{
"title": "The freeCodeCamp Guide",
"id": "5a187d4019a2ae635c8afa7c",
"description": [
[
"",
"",
"The freeCodeCamp Guide is a collection of easy-to-understand guides to programming tools.",
"https://github.com/freeCodeCamp/guides"
]
],
"challengeSeed": [],
"tests": [],
"type": "Waypoint",
"challengeType": 7,
"isRequired": false
}
]
}

View File

@ -0,0 +1,973 @@
{
"name": "System Design and Concept Questions",
"order": 3,
"time": "",
"helpRoom": "HelpJavaScript",
"challenges": [
{
"id": "59874fc749228906236a3275",
"title": "Array.prototype.map",
"description": [
{
"subtitle": "Flooring an Array",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1.32, 2.43, 3.9]\n .map(Math.floor);\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>1.32 2.43 3.9</code></pre>",
"<pre><code class='language-javascript'>['1.32', '2.43', '3.9']</code></pre>",
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
"<pre><code class='language-javascript'>'1 2 3'</code></pre>"
],
"answer": 2,
"explanation": "The map function takes a callback function as it's first parameter and applies that function against every value inside the array. In this example, our callback function is the <code>Math.floor</code> function which will truncate the decimal points of all the numbers and convert them to integers."
},
{
"subtitle": "Custom Map Functions",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(a => [a.toUpperCase()]);\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[['A'], ['B'], ['C']]</code></pre>",
"<pre><code class='language-javascript'>['A', 'B', 'C']</code></pre>",
"<pre><code class='language-javascript'>['a', 'b', 'c]</code></pre>",
"<pre><code class='language-javascript'>'ABC'</code></pre>"
],
"answer": 0,
"explanation": "The map function will return a new array with each element equal to the old element ran through a callback function. Our callback function takes our original element, changes it to a upper case, and then wraps it in an array; thus, leaving us with <code>[['A'], ['B'], ['C']]</code>"
},
{
"subtitle": "Maps on Maps",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [[4, 1], [2, 0], [3, 3]]\n .map(a => \n a.map(b => b % 2)[0] + a.map(b => b - 1)[1]\n )\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[[0, 1], [0, 0], [1, 1]]</code></pre>",
"<pre><code class='language-javascript'>[[0, 0], [0, -1], [1, 2]]</code></pre>",
"<pre><code class='language-javascript'>[1, 1, 2]</code></pre>",
"<pre><code class='language-javascript'>[0, -1, 3]</code></pre>"
],
"answer": 3,
"explanation": "This answer can be explained by first looking at the example of what happens with the first element in our array, <code>[4, 1]</code>. Our first map callback will run a mod 2 map function over <code>[4, 1]</code> leaving us with a new array of <code>[0, 1]</code>. The second map call which is inside our callback will subtract 1 from every element, leaving us with <code>[3, 0]</code>. Last, we take element at index 0, <code>0</code>, and add it to element of index 1 from our second map function, <code>0</code>, leaving us with 0; thus, after the first iteration of the top level map function, we are left with an array that looks like so: <code>[1, [2, 0], [3, 3]]</code>. We simply keep doing that logic for the other elements until we finish: <code>[1, -1, [3, 3]]</code>, and <code>[1, -1, 3]</code>"
},
{
"subtitle": "Words Containing 'a'",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['apple', 'dog', 'cat']\n .map((a, i) => \n a.indexOf('a') !== -1 ? i : null)\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[0, -1, 1]</code></pre>",
"<pre><code class='language-javascript'>[0, null, 2]</code></pre>",
"<pre><code class='language-javascript'>[null, null, null]</code></pre>",
"<pre><code class='language-javascript'>[-1, null, 2]</code></pre>"
],
"answer": 1,
"explanation": "This map example will return an array where each elements of the new array is either the original array index when the element contains the character 'a'; otherwise, an element of null for any words that do not have the character 'a'."
},
{
"subtitle": "Accessing the Original Array Elements",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3]\n .map((a, _, o) => a + o[0])\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[1, 2, 3]</code></pre>",
"<pre><code class='language-javascript'>[0, 0, 0]</code></pre>",
"<pre><code class='language-javascript'>[3, 2, 1]</code></pre>",
"<pre><code class='language-javascript'>[2, 3, 4]</code></pre>"
],
"answer": 3,
"explanation": "This map example will add the value of the first element in the original array to all the other elements in the array."
},
{
"subtitle": "More Map Hacking",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [8, 5, 3]\n .map((a, i, o) => o[o.length - i - 1])\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[3, 5, 8]</code></pre>",
"<pre><code class='language-javascript'>[5, 3, 8]</code></pre>",
"<pre><code class='language-javascript'>[8, 5, 3]</code></pre>",
"<pre><code class='language-javascript'>[3, 8, 5]</code></pre>"
],
"answer": 0,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
},
{
"subtitle": "Custom Scoping",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = ['a', 'b', 'c']\n .map(function(a) { return this[a]; }, {a: 9, b: 3, c: 1})\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>['a', 'b', 'c']</code></pre>",
"<pre><code class='language-javascript'>[9, 3, 1]</code></pre>",
"<pre><code class='language-javascript'>[3, 9, 1]</code></pre>",
"<pre><code class='language-javascript'>[{a: 9}, {b: 3}, {c: 1}]</code></pre>"
],
"answer": 1,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
},
{
"subtitle": "Reversing in Map, Just Because",
"question": "What will the following code print out?\n<pre><code class='language-javascript'>const results = [1, 2, 3, 4, 5]\n .map((a, _, o) => o.reverse() && a)\nconsole.log(results);</code></pre>",
"choices": [
"<pre><code class='language-javascript'>[5, 4, 3, 2, 1]</code></pre>",
"<pre><code class='language-javascript'>[5, 2, 3, 5, 1]</code></pre>",
"<pre><code class='language-javascript'>[1, 2, 3, 4, 5]</code></pre>",
"<pre><code class='language-javascript'>[1, 4, 3, 2, 5]</code></pre>"
],
"answer": 3,
"explanation": "This map example will reverse the array. The third argument to the map callback function is the original array; therefore, we can use the current index in the map function, and work our way backwards from the end of the array using the o.length."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a916843a9178457a6f1281f",
"title": "General questions",
"description": [
{
"subtitle": "Data Structure stack",
"question": "A stack data structure obeys the principles of Last in First Out (LIFO) true or false",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>"
],
"answer": 0,
"explanation": "true"
},
{
"subtitle": "Sorting algorithm",
"question": "Which of the following is not a common sorting algorithm ?",
"choices": [
"<pre><code class='language-javascript'>Bubble Sort</code></pre>",
"<pre><code class='language-javascript'>QuickSort</code></pre>",
"<pre><code class='language-javascript'>HeapSort</code></pre>",
"<pre><code class='language-javascript'>Branch Sort</code></pre>"
],
"answer": 3,
"explanation": "Branch sort is not a sorting algorithm"
},
{
"subtitle": "Persistent storage",
"question": "CRUD operation stand for ?",
"choices": [
"<pre><code class='language-javascript'>Create, Read, Update, Delete</code></pre>",
"<pre><code class='language-javascript'>Copy, Reduce, Update, Define</code></pre>",
"<pre><code class='language-javascript'>Create, Rich, Unique, Document</code></pre>",
"<pre><code class='language-javascript'>Cancel, Reduce, Unify, Dispose</code></pre>"
],
"answer": 0,
"explanation": "CRUD stands for Create - Read - Update and Delete and are the four basic operations of persistent storage"
},
{
"subtitle": "Numeric types",
"question": "Select the correct Numeric types to their correct size.",
"choices": [
"<pre><code class='language-javascript'>Byte - 8 bits, long - 64 bits,int - 32 bits, short - 16 bits.</code></pre>",
"<pre><code class='language-javascript'>Byte - 8 bits, long - 32 bits ,int - 64 bits, short - 16 bits.</code></pre>",
"<pre><code class='language-javascript'>Byte - 8 bits, long - 16 bits ,int - 32 bits, short - 64 bits.</code></pre>",
"<pre><code class='language-javascript'>Byte - 32 bits, long - 8 bits ,int - 64 bits, short - 16 bits.</code></pre>"
],
"answer": 0,
"explanation": "byte 8 bits, short 16 bits, int 32 bits, long 64 bits."
},
{
"subtitle": "Software architecture pattern",
"question": "The MVC software architectural pattern stands for ?",
"choices": [
"<pre><code class='language-javascript'>MeanStack - View - Class</code></pre>",
"<pre><code class='language-javascript'>Modal - Vector - Control</code></pre>",
"<pre><code class='language-javascript'>Model - View - Controller</code></pre>",
"<pre><code class='language-javascript'>Mapped - Volume - Content</code></pre>"
],
"answer": 2,
"explanation": "The MVC pattern is used to keep separate three main components of an application, the idea being for example the data or 'Model' does not need to know what the 'View' or presentation of that data is doing and vice versa, with the 'Controller' handling any logic or input from the user to manipulate the 'Model'."
},
{
"subtitle": "XPath navigation",
"question": "The XPath syntax is used to traverse data stored in which format",
"choices": [
"<pre><code class='language-javascript'>XML</code></pre>",
"<pre><code class='language-javascript'>JSON</code></pre>",
"<pre><code class='language-javascript'>Xtend</code></pre>",
"<pre><code class='language-javascript'>Text</code></pre>"
],
"answer": 0,
"explanation": "is used to navigate nodes and attributes within an XML document and stands for XML Path Language."
},
{
"subtitle": "Functions and side effects",
"question": "If a function is said to have side-effects it is expected to ?",
"choices": [
"<pre><code class='language-javascript'>Only return after an enclosed inner function has returned</code></pre>",
"<pre><code class='language-javascript'>Contain 'Blocking' code which can affect the stability of the program</code></pre>",
"<pre><code class='language-javascript'>Modify some kind of state outside of its own scope such as a global variable or change the value of its own arguments.</code></pre>",
"<pre><code class='language-javascript'>Have high algorithm complexity.</code></pre>"
],
"answer": 2,
"explanation": "Other charateristics of side-effects would be writing data to the log, interacting with users or systems on the same network and calling other functions with side-effects."
},
{
"subtitle": "Time-Complexity",
"question": "The term 'Time-Complexity' relates to ?",
"choices": [
"<pre><code class='language-javascript'>HTTP requests</code></pre>",
"<pre><code class='language-javascript'>Algorithms</code></pre>",
"<pre><code class='language-javascript'>Inheritance</code></pre>",
"<pre><code class='language-javascript'>Consuming API's</code></pre>"
],
"answer": 1,
"explanation": "Algorithm Time-Complexity is the total amount of time needed for an algorithm to run till full completion and is more often expressed with 'big-O-notation'."
},
{
"subtitle": "Find the odd",
"question": "Which of the following programming languages is the odd one out ?",
"choices": [
"<pre><code class='language-javascript'>C#</code></pre>",
"<pre><code class='language-javascript'>Java</code></pre>",
"<pre><code class='language-javascript'>Cobol</code></pre>",
"<pre><code class='language-javascript'>PHP</code></pre>"
],
"answer": 3,
"explanation": "PHP is generally referred to as an interpreted language where as the other three are considered languages generally processed by compilers."
},
{
"subtitle": "Find the odd, again",
"question": "Which in the following list is the odd one out ?",
"choices": [
"<pre><code class='language-javascript'>Boolean</code></pre>",
"<pre><code class='language-javascript'>Character</code></pre>",
"<pre><code class='language-javascript'>Array</code></pre>",
"<pre><code class='language-javascript'>Null</code></pre>"
],
"answer": 2,
"explanation": "An array in most languages is considered an object where as the other three are primitive data types."
},
{
"subtitle": "Programming languages paradigms",
"question": "Object-oriented and Functional are said to be programming language paradigms which of the following isn't a language paradigm.",
"choices": [
"<pre><code class='language-javascript'>Procedural</code></pre>",
"<pre><code class='language-javascript'>Imperative</code></pre>",
"<pre><code class='language-javascript'>Declarative</code></pre>",
"<pre><code class='language-javascript'>Instance</code></pre>"
],
"answer": 3,
"explanation": "Instance is not a recognised programming paradigm."
},
{
"subtitle": "UML",
"question": "UML or Universal Modeling Language is a language created for?",
"choices": [
"<pre><code class='language-javascript'>Creating database schemas.</code></pre>",
"<pre><code class='language-javascript'>Software visualization using diagrams.</code></pre>",
"<pre><code class='language-javascript'>Simplifying multi language software applications.</code></pre>",
"<pre><code class='language-javascript'>Integration of cross-platform systems on one network.</code></pre>"
],
"answer": 1,
"explanation": "UML is used for software modeling in diagram form including Class diagrams, Object diagrams and Use case diagrams among others."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a91690fa9178457a6f12820",
"title": "CSS questions part 1",
"description": [
{
"subtitle": "Elements properties",
"question": "Which properties do inline elements not possess under normal document flow.",
"choices": [
"<pre>overflow, left or right margins</pre>",
"<pre>border-radius, z-index</pre>",
"<pre>font-size, animation</pre>",
"<pre>width, top or bottom margins</pre>"
],
"answer": 3,
"explanation": "An inline element will only take up the width of the inner content."
},
{
"subtitle": "CSS rules",
"question": "What will the following css rule select?\n<pre><code class='language-javascript'>.test > div</code> {\n...\n}</code></pre>",
"choices": [
"<pre><code class='language-javascript'>Selects all divs within elements with the class of test.</code></pre>",
"<pre><code class='language-javascript'>Selects all divs outside of elements with the class of test.</code></pre>",
"<pre><code class='language-javascript'>Selects only divs that are immediate children of elements with the class of test.</code></pre>",
"<pre><code class='language-javascript'>This would not be considered a valid selector.</code></pre>"
],
"answer": 2,
"explanation": "eg: \n<pre><code class='language-html'>&lt;div class='test'&gt;\n&lt;div class='box'&gt;\n&lt;div class='content'&gt;...&lt;/div&gt;\n&lt;/div&gt;\n&lt;div class='box'&gt;\n&lt;div class='content'&gt;...&lt;/div&gt;\n&lt;/div&gt;\n&lt;/div&gt;</code></pre>\n\nWould target only the elements with a class of 'box' as these are the direct children of 'test'."
},
{
"subtitle": "Overriding properties",
"question": "Which keyword would you add to the end of a style rule to override another Css style for a specific element ?",
"choices": [
"<pre><code class='language-javascript'>*override</code></pre>",
"<pre><code class='language-javascript'>*overrideAll</code></pre>",
"<pre><code class='language-javascript'>!vital</code></pre>",
"<pre><code class='language-javascript'>!important</code></pre>"
],
"answer": 3,
"explanation": "For example if you wanted all the paragraph tags in a specific class to have the colour blue instead of black\n<pre><code class='language-javascript'></code>.myClass p {\ncolor: blue !important\n}</code></pre>"
},
{
"subtitle": "Preprocessor CSS",
"question": "Which is not considered a Css preprocessor?",
"choices": [
"<pre><code class='language-javascript'>Less</code></pre>",
"<pre><code class='language-javascript'>Sass</code></pre>",
"<pre><code class='language-javascript'>Stylus</code></pre>",
"<pre><code class='language-javascript'>Express</code></pre>"
],
"answer": 3,
"explanation": "Express is an application framework for Node.js"
},
{
"subtitle": "CSS Box Model",
"question": "Which is not a property of the Css 'Box Model'?",
"choices": [
"<pre><code class='language-javascript'>Border</code></pre>",
"<pre><code class='language-javascript'>Padding</code></pre>",
"<pre><code class='language-javascript'>Margin</code></pre>",
"<pre><code class='language-javascript'>Outline</code></pre>"
],
"answer": 3,
"explanation": "Content is the fourth property of the box model not outline."
},
{
"subtitle": "CSS positioning",
"question": "Absolute positioning in Css removes an element from the normal document flow true/false?",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>"
],
"answer": 0,
"explanation": "Giving an element absolute positioning removes it from the normal document flow completely allowing positioning attributes top, left, bottom."
},
{
"subtitle": "CSS selector",
"question": "With this Css Selector it is possible to select every element in a document.",
"choices": [
"<pre><code class='language-javascript'>Body</code></pre>",
"<pre><code class='language-javascript'>Universal</code></pre>",
"<pre><code class='language-javascript'>Wildcard</code></pre>",
"<pre><code class='language-javascript'>SelectAll</code></pre>"
],
"answer": 1,
"explanation": "The Universal selector will select every element on a page and is denoted by <code>*{}</code>. note: The rule of specificity still applies, so a more specific selector can override the universal selector in a Css document."
},
{
"subtitle": "Font size in CSS",
"question": "Which is not a valid Css font size?",
"choices": [
"<pre><code class='language-javascript'>em</code></pre>",
"<pre><code class='language-javascript'>%</code></pre>",
"<pre><code class='language-javascript'>tp</code></pre>",
"<pre><code class='language-javascript'>px</code></pre>"
],
"answer": 2,
"explanation": "tp is not valid this should be pt."
},
{
"subtitle": "CSS clear property",
"question": "The Css 'clear' property fulfills which task?",
"choices": [
"<pre><code class='language-javascript'>Allows transparency of an element.</code></pre>",
"<pre><code class='language-javascript'>Prevents prior properties of the selector from taking effect.</code></pre>",
"<pre><code class='language-javascript'>Positions an element clear of a siblings margins and borders.</code></pre>",
"<pre><code class='language-javascript'>Sets which sides of an element floating elements are not allowed to be floated.</code></pre>"
],
"answer": 3,
"explanation": "The clear property has the following values available: both, left, right, inherit, initial and none."
},
{
"subtitle": "CSS sudo-class",
"question": "An example of a sudo-class of a ul element written in Css would be defined?",
"choices": [
"<pre><code class='language-javascript'>ul:first-child</code></pre>",
"<pre><code class='language-javascript'>ul..first-child</code></pre>",
"<pre><code class='language-javascript'>ul::first-child</code></pre>",
"<pre><code class='language-javascript'>ul first-child</code></pre>"
],
"answer": 0,
"explanation": "First answer : Would be correct of a sudo-class.<br />Second answer : Would be an error of syntax.<br />Third answer: The double colon would be an example of a sudo element used with the likes of <code>::before</code> and <code>::after</code> which are examples of content.<br />Fourth answer : This would relate to html tag elements of which there is no first-child tag."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a91a167a9178457a6f12821",
"title": "CSS questions part 2",
"description": [
{
"subtitle": "CSS selector",
"question": "An entire Css selector and declaration block whithin a Css document eg:<code><br /> .container div p {<br />position: relative;<br />width: 300px;<br />margin: auto;<br />color: #ffffff;<br />}</code><br /> is referred to as?",
"choices": [
"<pre><code class='language-javascript'>Base-Block</code></pre>",
"<pre><code class='language-javascript'>Selection Properties</code></pre>",
"<pre><code class='language-javascript'>Selector Group</code></pre>",
"<pre><code class='language-javascript'>Ruleset</code></pre>"
],
"answer": 3,
"explanation": "The selectors name and properties are collectively called a Ruleset."
},
{
"subtitle": "CSS Browser compatibility",
"question": "Which is not a valid Css prefix to ensure browser compatibility?",
"choices": [
"<pre><code class='language-javascript'>-webkit-</code></pre>",
"<pre><code class='language-javascript'>-win-</code></pre>",
"<pre><code class='language-javascript'>-moz-</code></pre>",
"<pre><code class='language-javascript'>-o-</code></pre>"
],
"answer": 1,
"explanation": "<code>-win-</code> is incorrect, <code>-webkit-</code> (Chrome, Safari, ioS and modern versions of Opera), <code>-moz-</code> (Firefox), <code>-o-</code> (Older versions of Opera), the other would be <code>-ms-</code> used for (IE and Microsoft Edge)."
},
{
"subtitle": "CSS 'text-transform' property",
"question": "The Css property 'text-transform' is mainly used for?",
"choices": [
"<pre><code class='language-javascript'>Alteration of text letter case.</code></pre>",
"<pre><code class='language-javascript'>Changing the alignment of text.</code></pre>",
"<pre><code class='language-javascript'>Increase/Decrease font size.</code></pre>",
"<pre><code class='language-javascript'>Transformation of font family.</code></pre>"
],
"answer": 0,
"explanation": "The values for the property 'text-transform' are, capitalize, full-width, inherit, lowercase, none and uppercase."
},
{
"subtitle": "CSS font-sizes",
"question": "If the default font size for a page is 12px, What is the pixel equivalent of 1.5em?",
"choices": [
"<pre><code class='language-javascript'>12.5px</code></pre>",
"<pre><code class='language-javascript'>9px</code></pre>",
"<pre><code class='language-javascript'>18px</code></pre>",
"<pre><code class='language-javascript'>6px</code></pre>"
],
"answer": 2,
"explanation": "1em is equivalent to the base or default font size therefore (12 * 1.5 = 18)."
},
{
"subtitle": "CCSS font weight",
"question": "In Css 'font-weight: bold;' is the same as?",
"choices": [
"<pre><code class='language-javascript'>font-weight: 400;</code></pre>",
"<pre><code class='language-javascript'>font-weight: 900</code></pre>",
"<pre><code class='language-javascript'>font-weight: 700</code></pre>",
"<pre><code class='language-javascript'>font-weight: 500</code></pre>"
],
"answer": 2,
"explanation": "The keyword 'bold' is the same as the numerical value 700."
},
{
"subtitle": "CSS ruleset",
"question": "Given this ruleset <code><br />.testDiv {<br />width: 20%;<br />height: 20%;<br />content: 'add this text'<br />}</code><br />What would happen with the content properties text?",
"choices": [
"<pre><code class='language-javascript'>Nothing</code></pre>",
"<pre><code class='language-javascript'>Appended to any text contained in element with class of testDiv.</code></pre>",
"<pre><code class='language-javascript'>Prepended to any text contained in element with class of testDiv.</code></pre>",
"<pre><code class='language-javascript'>Overwrite any text contained in element with class of testDiv.</code></pre>"
],
"answer": 0,
"explanation": "Nothing would appear on the page, the content property needs to be used with sudo elements like <code>::after</code> or <code>::before</code> eg:<br /><code>.testDiv {<br />width: 20%;<br />height: 20%;\n}\n.testDiv::after {\ncontent: 'add this text'\n}</code>"
},
{
"subtitle": "CSS match selector",
"question": "What would the following Css selector match?<br /><code>section + p</code>",
"choices": [
"<pre><code class='language-javascript'>All &lt;section&gt; and &lt;p&gt; tags.</code></pre>",
"<pre><code class='language-javascript'>All &lt;p&gt; tags within a &lt;section&gt; tag.</code></pre>",
"<pre><code class='language-javascript'>All &lt;p&gt; tags placed immediately after a &lt;section&gt; tag.</code></pre>",
"<pre><code class='language-javascript'>Not a valid selector.</code></pre>"
],
"answer": 2,
"explanation": "<pre><code class='language-javascript'>&lt;p&gt;First Paragraph&lt;/p&gt;<br />&lt;section&gt;...&lt;/section&gt;<br />&lt;p&gt;Second Paragraph&lt;/p&gt;<br />&lt;p&gt;Third Paragraph&lt;/p&gt;</code></pre><br />Only the second paragraph tag will be selected and matched."
},
{
"subtitle": "How to incorporte CSS into web document",
"question": "How many different ways is it possible to incorporate Css into a web document?",
"choices": [
"<pre><code class='language-javascript'>1</code></pre>",
"<pre><code class='language-javascript'>2</code></pre>",
"<pre><code class='language-javascript'>3</code></pre>",
"<pre><code class='language-javascript'>4</code></pre>"
],
"answer": 2,
"explanation": "Currently Css can be used 'Inline' as a style attribute of an Html element, 'Embedded' in a style tag of a document and 'Imported' as an external file with the link tag element."
},
{
"subtitle": "Using target in css",
"question": "What would <code>[role=contentinfo] {...}</code> target in Css?",
"choices": [
"<pre><code class='language-javascript'>Any element with the role attribute of contentinfo.</code></pre>",
"<pre><code class='language-javascript'>Any element within a &lt;span&gt; tag.</code></pre>",
"<pre><code class='language-javascript'>Any element within a &lt;span&gt; tag with the role attribute of contentinfo.</code></pre>",
"<pre><code class='language-javascript'>This would only be valid using Sass or Scss.</code></pre>"
],
"answer": 0,
"explanation": "The square bracket notation is used to target elements with specific attributes."
},
{
"subtitle": "CSS positioning",
"question": "Which is not a value for 'position' in css?",
"choices": [
"<pre><code class='language-javascript'>Absolute</code></pre>",
"<pre><code class='language-javascript'>Static</code></pre>",
"<pre><code class='language-javascript'>Responsive</code></pre>",
"<pre><code class='language-javascript'>inherit</code></pre>"
],
"answer": 2,
"explanation": "There is no such positioning as responsive, currently there is (absolute, fixed, inherit, relative and static)."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a91b5bfa9178457a6f12822",
"title": "Javascript questions part 1",
"description": [
{
"subtitle": "JavaScript Array method",
"question": "which of the following is not an Array method?",
"choices": [
"<pre><code class='language-javascript'>pop()</code></pre>",
"<pre><code class='language-javascript'>unshift()</code></pre>",
"<pre><code class='language-javascript'>split()</code></pre>",
"<pre><code class='language-javascript'>every()</code></pre>"
],
"answer": 2,
"explanation": "<code>split()</code> is a string method<br /><code>pop()</code> removes from the end of an array<br /><code>unshift()</code> adds to the front of an array<br />and <code>every()</code> returns a true or false value for each element in an array."
},
{
"subtitle": "JavaScript ES6 feature",
"question": "ES6 Arrow functions written on one line require no return statement.",
"choices": [
"<pre><code class='language-javascript'>True</code></pre>",
"<pre><code class='language-javascript'>False</code></pre>"
],
"answer": 0,
"explanation": "True"
},
{
"subtitle": "JavaScript strict syntax",
"question": "Where is the correct place to insert the \"use strict\" expression.",
"choices": [
"<pre><code class='language-javascript'>Before declaring a variable</code></pre>",
"<pre><code class='language-javascript'>At the start of a script or function</code></pre>",
"<pre><code class='language-javascript'>It is used inline within an HTML element</code></pre>",
"<pre><code class='language-javascript'>Within a Css selector</code></pre>"
],
"answer": 1,
"explanation": "The \"use strict\"; expression should be placed at the start of a script for global scope or\nwithin a function for local scope."
},
{
"subtitle": "JavaScript equality",
"question": "The following code will output?<br /><code>const x = '7'<br />const y = 7<br />console.log(x == y)</code>",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>",
"<pre><code class='language-javascript'>NaN</code></pre>",
"<pre><code class='language-javascript'>undefined</code></pre>"
],
"answer": 0,
"explanation": "true, if triple equals '===' was used it would then evaluate to false."
},
{
"subtitle": "JavaScript modules",
"question": "In which of the following can you expect to see the <code>require()</code> function?",
"choices": [
"<pre><code class='language-javascript'>Vanilla Javascript</code></pre>",
"<pre><code class='language-javascript'>React.js</code></pre>",
"<pre><code class='language-javascript'>Node.js</code></pre>",
"<pre><code class='language-javascript'>Jquery</code></pre>"
],
"answer": 2,
"explanation": "<code>require()</code> is built into Node.js in order to load modules for use with an application."
},
{
"subtitle": "JavaScript recursive methods",
"question": "What is the main function or job of a 'base case' in a typical recursive method ?",
"choices": [
"<pre><code class='language-javascript'>To reduce the algorithm complexity of the function.</code></pre>",
"<pre><code class='language-javascript'>To terminate the recursion.</code></pre>",
"<pre><code class='language-javascript'>To keep track of each invocation of the function on the stack.</code></pre>",
"<pre><code class='language-javascript'>To return null.</code></pre>"
],
"answer": 1,
"explanation": "To allow the recursive function to terminate and inititate the popping off of the stack of each function call pushed upon it."
},
{
"subtitle": "JavaScript framework",
"question": "In which Javascript framework will you find the ng style of attributes?",
"choices": [
"<pre><code class='language-javascript'>Jquery</code></pre>",
"<pre><code class='language-javascript'>React</code></pre>",
"<pre><code class='language-javascript'>Angular</code></pre>",
"<pre><code class='language-javascript'>Ember</code></pre>"
],
"answer": 2,
"explanation": "The ng- style prefix is used to denote an angularJS directive."
},
{
"subtitle": "JavaScript syntax",
"question": "The following code will return 24 true or false?<br /><code>function multiply(num1, num2) {<br />return<br />num1 * num2;<br />}<br />multiply(4,6)</code>",
"choices": [
"<pre><code class='language-javascript'>True</code></pre>",
"<pre><code class='language-javascript'>False</code></pre>"
],
"answer": 1,
"explanation": "The function will return undefined before it reaches the multiplication of the two arguments."
},
{
"subtitle": "JavaScript callback",
"question": "A callback function is also known as?",
"choices": [
"<pre><code class='language-javascript'>Loopback function</code></pre>",
"<pre><code class='language-javascript'>Higher-order function</code></pre>",
"<pre><code class='language-javascript'>Recursive function</code></pre>",
"<pre><code class='language-javascript'>Pure Function</code></pre>"
],
"answer": 1,
"explanation": "Also Known as a Higher-order function a callback function can be passed to another function as a parameter and is called inside that function."
},
{
"subtitle": "JavaScript syntax, again",
"question": "Javascript is case sensitive true or false?",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>"
],
"answer": 0,
"explanation": "true"
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a92c913a9178457a6f12823",
"title": "Javascript questions part 2",
"description": [
{
"subtitle": "JavaScript pop up",
"question": "Which is not a pop up box in JavaScript",
"choices": [
"<pre><code class='language-javascript'>Confirm Box</code></pre>",
"<pre><code class='language-javascript'>Alert Box</code></pre>",
"<pre><code class='language-javascript'>Message Box</code></pre>",
"<pre><code class='language-javascript'>Prompt Box</code></pre>"
],
"answer": 2,
"explanation": "Message Box."
},
{
"subtitle": "JavaScript Loops",
"question": "Which of the following is not a looping format in javascript",
"choices": [
"<pre><code class='language-javascript'>For</code></pre>",
"<pre><code class='language-javascript'>While</code></pre>",
"<pre><code class='language-javascript'>Next</code></pre>",
"<pre><code class='language-javascript'>Do-While</code></pre>"
],
"answer": 2,
"explanation": "Next is not a loop available in javascript."
},
{
"subtitle": "JavaScript types",
"question": "What is the result of the following code?<code>\nconsole.log( 4 + 4 + \"2\" )</code>;",
"choices": [
"<pre><code class='language-javascript'>\"82\"</code></pre>",
"<pre><code class='language-javascript'>10</code></pre>",
"<pre><code class='language-javascript'>82</code></pre>",
"<pre><code class='language-javascript'>\"10\"</code></pre>"
],
"answer": 0,
"explanation": "The first two integers will be added as normal then the string will be concatenated to the result of 8 giving \"82\"."
},
{
"subtitle": "JavaScript types",
"question": "What is the result of the following code?<code>\nconsole.log( \"3\" + 6 + 6 );</code>",
"choices": [
"<pre><code class='language-javascript'>15</code></pre>",
"<pre><code class='language-javascript'>\"15\"</code></pre>",
"<pre><code class='language-javascript'>\"366\"</code></pre>",
"<pre><code class='language-javascript'>366</code></pre>"
],
"answer": 2,
"explanation": "As the equation begins with a string, each integer will be converted and appended in string form giving \"366\""
},
{
"subtitle": "JavaScript Event loop",
"question": "Which best describes the function of the Javascript event loop?",
"choices": [
"<pre><code class='language-javascript'>To Handle synchronous code one line at a time in the main script.</code></pre>",
"<pre><code class='language-javascript'>To remove any blocking functions accidentally pushed on to the call stack.</code></pre>",
"<pre><code class='language-javascript'>To constantly monitor if the call stack is empty and then invoke any asynchronous functions from the event queue.</code></pre>",
"<pre><code class='language-javascript'>A mechanism to best decide how to terminate any looping structure.</code></pre>"
],
"answer": 2,
"explanation": "Briefly the event loop constantly runs to monitor state between the callstack, the event table and the event queue. When asynchronous code is executed it\nis placed on to the event table only to be executed as and when a specific event occurs, when it does it is then placed on the event queue until the call\nstack is empty then when invoked, moved from the queue to the callstack."
},
{
"subtitle": "JavaSript type",
"question": "<code>console.log(typeof(NaN))</code> Will log?",
"choices": [
"<pre><code class='language-javascript'>false</code></pre>",
"<pre><code class='language-javascript'>null</code></pre>",
"<pre><code class='language-javascript'>number</code></pre>",
"<pre><code class='language-javascript'>undefined</code></pre>"
],
"answer": 2,
"explanation": "Despite standing for Not a Number NaN is still regarded as a numeric type."
},
{
"subtitle": "JavaScript ES6 operators",
"question": "What will the following log?<code><br />let x = 'teststring';<br />console.log([...x]);</code>",
"choices": [
"<pre><code class='language-javascript'>[\"t\",\"e\",\"s\",\"t\",\"s\",\"t\",\"r\",\"i\",\"n\",\"g\"]</code></pre>",
"<pre><code class='language-javascript'>uncaught syntax error</code></pre>",
"<pre><code class='language-javascript'>[\"teststring\"]</code></pre>",
"<pre><code class='language-javascript'>t e s t s t r i n g</code></pre>"
],
"answer": 0,
"explanation": "The spread syntax introduced in es6 can be used to iterate through each character of a string, and here stored in an array similar to calling <code>x.split(\"\")</code>"
},
{
"subtitle": "ES6 let / const declarations",
"question": "What will the following code log?<code><br />function myFunction() {<br />const a = 'variableA'<br />if( 3 > 1) {<br />let b = 'variableB'<br />}<br />console.log(a)<br />console.log(b)<br />}<br />myFunction();</code>",
"choices": [
"<pre><code class='language-javascript'>variableA, variableB</code></pre>",
"<pre><code class='language-javascript'>variableA</code></pre>",
"<pre><code class='language-javascript'>variableB, variableA</code></pre>",
"<pre><code class='language-javascript'>variableA, Uncaught ReferenceError: b is not defined</code></pre>"
],
"answer": 3,
"explanation": "Due to the keywords let and const being block scoped rather than just locally function scoped like var, the variable b will be garbage collected after the\nconditional if statement has finished and will no longer exist for the console.log() method."
},
{
"subtitle": "JavaSript function arguments",
"question": "The following code will return?<code><br />function getsum(num1 = 1, num2 = 1) {<br />return num1 + num2;<br />}<br />getsum(3);</code>",
"choices": [
"<pre><code class='language-javascript'>4</code></pre>",
"<pre><code class='language-javascript'>6</code></pre>",
"<pre><code class='language-javascript'>2</code></pre>",
"<pre><code class='language-javascript'>5</code></pre>"
],
"answer": 0,
"explanation": "Due to only one argument being passed this will override the first default parameter giving num1 the value of 3 + num2 default value of 1.\nIf the function were to be executed without any arguments at all both defaults would be used and return 2."
},
{
"subtitle": "JavaSript inheritance",
"question": "All Javascript objects inherit properties and methods from a class true or false?",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>"
],
"answer": 1,
"explanation": "Due to only one argument being passed this will override the first default parameter giving num1 the value of 3 + num2 default value of 1.\nIf the function were to be executed without any arguments at all both defaults would be used and return 2."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a933ce3a9178457a6f12824",
"title": "Networking questions part 1",
"description": [
{
"subtitle": "Address identification",
"question": "00:26:2D:55:42:1f is an example of what?",
"choices": [
"<pre>MAC Address</pre>",
"<pre>IPv4 Address</pre>",
"<pre>IPv6 Address</pre>",
"<pre>A wireless protocol</pre>"
],
"answer": 0,
"explanation": "A valid MAC Address."
},
{
"subtitle": "OSI networking model",
"question": "Which one of the following is not part of the seven layer OSI networking model.",
"choices": [
"<pre>Application</pre>",
"<pre>Presentation</pre>",
"<pre>Session</pre>",
"<pre>Protocol</pre>",
"<pre>Network</pre>",
"<pre>Data Link</pre>",
"<pre>Physical</pre>"
],
"answer": 3,
"explanation": "Protocol is not part of the OSI networking model layer 4 should be the transport layer."
},
{
"subtitle": "RAID",
"question": "In networking a RAID implementation relates to?",
"choices": [
"<pre>Wireless standards</pre>",
"<pre>Password policies</pre>",
"<pre>Remote access</pre>",
"<pre>Fault tolerance</pre>"
],
"answer": 3,
"explanation": "RAID stands for Redundant array of inexpensive disks and is a model that allows servers to\nendure the failure of one or more hard disks without interuption to services and resources."
},
{
"subtitle": "Server status",
"question": "Your console or terminal throws up a 404 error, this means?",
"choices": [
"<pre>Upgrade required</pre>",
"<pre>Not found</pre>",
"<pre>Gateway Timeout</pre>",
"<pre>No Response</pre>"
],
"answer": 1,
"explanation": "This error informs you that an internal or external resource has not been found and can not be loaded into a page or application."
},
{
"subtitle": "Server Status, again",
"question": "Your console or terminal throws up a 500 error, this means?",
"choices": [
"<pre>Internal Server Error</pre>",
"<pre>Proxy Authentication Required</pre>",
"<pre>Upgrade Required</pre>",
"<pre>Too Many Requests</pre>"
],
"answer": 0,
"explanation": "A generic error message which refers to an error on the webserver when no precise detail is available."
},
{
"subtitle": "HTTP methods",
"question": "GET and POST are important HTTP request methods which of the following list are Not an example of an HTTP request method?",
"choices": [
"<pre>HEAD</pre>",
"<pre>PUT</pre>",
"<pre>BODY</pre>",
"<pre>DELETE</pre>"
],
"answer": 2,
"explanation": "HEAD is similar to the Get method but returns no response body, PUT is used to replace and update a specified resource, DELETE will delete a resource,\nthere is no such method as a BODY request."
},
{
"subtitle": "Loopback",
"question": "In networking which of the following is considered to be a loopback ip address or 'localhost'?",
"choices": [
"<pre>172.0.0.1</pre>",
"<pre>127.0.0.1</pre>",
"<pre>10.0.0.0</pre>",
"<pre>192.168.0.0</pre>"
],
"answer": 1,
"explanation": "127.0.0.1 is the loopback address or localhost, option a is an example of a public address and options c and d are examples of private network addresses."
},
{
"subtitle": "Network & Security Architecture",
"question": "Ring, Star, Mesh and Bus are all examples of?",
"choices": [
"<pre>Network topologies</pre>",
"<pre>Security Protocols for mobile development</pre>",
"<pre>Restful API's</pre>",
"<pre>File server storage methods</pre>"
],
"answer": 0,
"explanation": "A network topology is a logical and physical layout of how the network appears to the devices using it."
}
],
"tests": [],
"challengeType": 8
},
{
"id": "5a933d04a9178457a6f12825",
"title": "Networking questions part 2",
"description": [
{
"subtitle": "Default port for FTP",
"question": "In attempting to connect to an FTP (File Transfer Protocol) server and failing, which port can you check is open to troubleshoot the connection issue?",
"choices": [
"<pre><code class='language-javascript'>25</code></pre>",
"<pre><code class='language-javascript'>443</code></pre>",
"<pre><code class='language-javascript'>23</code></pre>",
"<pre><code class='language-javascript'>21</code></pre>"
],
"answer": 3,
"explanation": "Port 21 is traditionally used as the default port on a system for FTP."
},
{
"subtitle": "Network types",
"question": "Which of the following is not a type of network?",
"choices": [
"<pre><code class='language-javascript'>LAN</code></pre>",
"<pre><code class='language-javascript'>MAN</code></pre>",
"<pre><code class='language-javascript'>PAN</code></pre>",
"<pre><code class='language-javascript'>NAN</code></pre>"
],
"answer": 3,
"explanation": "NAN is not a current network type. LAN (Local Area Network), MAN (Metropolitan Area Network), PAN (Personal Area Network)."
},
{
"subtitle": "Subnet mask usage",
"question": "What is a subnet mask used for?",
"choices": [
"<pre><code class='language-javascript'>To hide the id of a wireless access point.</code></pre>",
"<pre><code class='language-javascript'>To identyfy the extended and host address.</code></pre>",
"<pre><code class='language-javascript'>To encrypt the broadcasting of ip addresses.</code></pre>",
"<pre><code class='language-javascript'>To connect to a vpn.</code></pre>"
],
"answer": 1,
"explanation": "A subnet mask is used along side an IP address in order to isolate the extended or 'subnet' of the network address and the host machine address."
},
{
"subtitle": "Network acronym",
"question": "What does NIC stand for?",
"choices": [
"<pre><code class='language-javascript'>Network Isolated Connection</code></pre>",
"<pre><code class='language-javascript'>Network Interconnect Cables</code></pre>",
"<pre><code class='language-javascript'>Network Interface Card</code></pre>",
"<pre><code class='language-javascript'>Network Interference Cause</code></pre>"
],
"answer": 2,
"explanation": "A Network Interface Card or (Network Interface Controller) is a hardware component that connects to a Pc or printer in order to\nconnect and be identified on a network."
},
{
"subtitle": "Default gateway",
"question": "A 'default gateway' provides a way for a local network to connect to a larger external network true or false?",
"choices": [
"<pre><code class='language-javascript'>true</code></pre>",
"<pre><code class='language-javascript'>false</code></pre>"
],
"answer": 0,
"explanation": "True this is usually the address of of an external router or switch."
},
{
"subtitle": "The ipconfig commad",
"question": "'ipconfig' is used for?",
"choices": [
"<pre><code class='language-javascript'>Reassigning ip addresses.</code></pre>",
"<pre><code class='language-javascript'>Tool for masking ip adresses.</code></pre>",
"<pre><code class='language-javascript'>Monitoring network traffic.</code></pre>",
"<pre><code class='language-javascript'>Identify address information of a machine on a network.</code></pre>"
],
"answer": 3,
"explanation": "ipconfig or ifconfig(linux) is a utility for gaining various address information of a computer on a network."
},
{
"subtitle": "Network terminology",
"question": "The term 'Latency' refers to?",
"choices": [
"<pre><code class='language-javascript'>The logical state of a network.</code></pre>",
"<pre><code class='language-javascript'>A loss of data expected in transfer over a network.</code></pre>",
"<pre><code class='language-javascript'>A measure of time delay between request and response experienced by a system.</code></pre>",
"<pre><code class='language-javascript'>The scope for expanding a network.</code></pre>"
],
"answer": 2,
"explanation": "Latency can affect host to host transfers http requests etc."
},
{
"subtitle": "Network terminology, again",
"question": "The term 'full duplex' refers to?",
"choices": [
"<pre><code class='language-javascript'>Two way data transfer but not at the same time.</code></pre>",
"<pre><code class='language-javascript'>Two way data transfer simultaneously.</code></pre>",
"<pre><code class='language-javascript'>One way data transfer at high speed.</code></pre>",
"<pre><code class='language-javascript'>One way data transfer with encryption</code></pre>"
],
"answer": 1,
"explanation": "An example of full duplex would be like a telephone conversation between two people."
}
],
"tests": [],
"challengeType": 8
}
]
}

View File

@ -0,0 +1,76 @@
/* eslint-disable no-self-compare */
// no import here as this runs without babel
const fs = require('fs');
const path = require('path');
const omit = require('lodash/omit');
const hiddenFile = /(^(\.|\/\.))|(.md$)/g;
function getFilesFor(dir) {
let targetDir = path.join(__dirname, dir);
return fs
.readdirSync(targetDir)
.filter(file => !hiddenFile.test(file))
.map(function(file) {
let superBlock;
if (fs.statSync(path.join(targetDir, file)).isFile()) {
return { file: file };
}
superBlock = file;
return getFilesFor(path.join(dir, superBlock)).map(function(data) {
return {
file: path.join(superBlock, data.file),
superBlock: superBlock
};
});
})
.reduce(function(files, entry) {
return files.concat(entry);
}, []);
}
function superblockInfo(filePath) {
let parts = (filePath || '').split('-');
let order = parseInt(parts[0], 10);
if (isNaN(order)) {
return { order: 0, name: filePath };
} else {
return {
order: order,
name: parts.splice(1).join('-')
};
}
}
// unpackFlag is an argument passed by the unpack script in unpack.js
// which allows us to conditionall omit translations when running
// the test suite and prevent schema related errors in the main fCC branch
module.exports = function getChallenges(challengesDir, unpackFlag) {
if (!challengesDir) {
challengesDir = 'challenges';
}
return getFilesFor(challengesDir).map(function(data) {
const challengeSpec = require('./' + challengesDir + '/' + data.file);
let superInfo = superblockInfo(data.superBlock);
challengeSpec.fileName = data.file;
challengeSpec.superBlock = superInfo.name;
challengeSpec.superOrder = superInfo.order;
challengeSpec.challenges = challengeSpec.challenges.map(challenge =>
omit(challenge, [
'betaSolutions',
'betaTests',
'hints',
'MDNlinks',
'null',
'rawSolutions',
'react',
'reactRedux',
'redux',
'releasedOn',
unpackFlag ? undefined : 'translations',
'type'
])
);
return challengeSpec;
});
};

29
curriculum/gulpfile.js Normal file
View File

@ -0,0 +1,29 @@
const gulp = require('gulp');
const util = require('gulp-util');
const jsonMinify = require('gulp-json-minify');
const babel = require('gulp-babel');
const rename = require('gulp-rename');
gulp.task('json:minify', function() {
return gulp.src('./challenges/**/*.json')
.pipe(jsonMinify())
.pipe(gulp.dest('dist/challenges/'))
.on('error', util.log);
});
gulp.task('babel-getChallenges', () =>
gulp.src('./getChallenges.js')
.pipe(babel({
presets: ['env']
}))
.pipe(gulp.dest('dist'))
);
gulp.task('babel', ['babel-getChallenges'], () =>
gulp.src('./package-entry.js')
.pipe(rename('./index.js'))
.pipe(babel({
presets: ['env']
}))
.pipe(gulp.dest('dist/'))
);

168
curriculum/index.js Normal file
View File

@ -0,0 +1,168 @@
/* eslint-disable no-process-exit */
require('babel-register');
require('dotenv').load();
const adler32 = require('adler32');
const Rx = require('rx');
const _ = require('lodash');
const createDebugger = require('debug');
const utils = require('../server/utils');
const getChallenges = require('./getChallenges');
const { validateChallenge } = require(
'./schema/challengeSchema'
);
const app = require('../server/server');
const log = createDebugger('fcc:seed');
// force logger to always output
// this may be brittle
log.enabled = true;
const dasherize = utils.dasherize;
const nameify = utils.nameify;
const Observable = Rx.Observable;
const Challenge = app.models.Challenge;
const destroyChallenges =
Observable.fromNodeCallback(Challenge.destroyAll, Challenge);
const createChallenges =
Observable.fromNodeCallback(Challenge.create, Challenge);
const Block = app.models.Block;
const destroyBlocks = Observable.fromNodeCallback(Block.destroyAll, Block);
const createBlocks = Observable.fromNodeCallback(Block.create, Block);
const arrToString = arr =>
Array.isArray(arr) ? arr.join('\n') : _.toString(arr);
Observable.combineLatest(
destroyChallenges(),
destroyBlocks()
)
.last()
.flatMap(function() { return Observable.from(getChallenges()); })
.flatMap(function(challengeSpec) {
const order = challengeSpec.order;
const blockName = challengeSpec.name;
const superBlock = challengeSpec.superBlock;
const superOrder = challengeSpec.superOrder;
const isBeta = !!challengeSpec.isBeta;
const isComingSoon = !!challengeSpec.isComingSoon;
const fileName = challengeSpec.fileName;
const helpRoom = challengeSpec.helpRoom || 'Help';
const time = challengeSpec.time;
const isLocked = !!challengeSpec.isLocked;
const message = challengeSpec.message;
const required = challengeSpec.required || [];
const template = challengeSpec.template;
const isPrivate = !!challengeSpec.isPrivate;
log('parsed %s successfully', blockName);
// challenge file has no challenges...
if (challengeSpec.challenges.length === 0) {
return Rx.Observable.just([{ block: 'empty ' + blockName }]);
}
const block = {
title: blockName,
name: nameify(blockName),
dashedName: dasherize(blockName),
superOrder,
superBlock,
superBlockMessage: message,
order,
time,
isLocked,
isPrivate
};
return createBlocks(block)
.map(block => {
log('successfully created %s block', block.name);
return challengeSpec.challenges
.map(function(challenge, index) {
challenge.name = nameify(challenge.title);
challenge.dashedName = dasherize(challenge.name);
challenge.checksum = adler32.sum(
Buffer(
challenge.title +
JSON.stringify(challenge.description) +
JSON.stringify(challenge.challengeSeed) +
JSON.stringify(challenge.tests)
)
);
if (challenge.files) {
challenge.files = _.reduce(challenge.files, (map, file) => {
map[file.key] = {
...file,
head: arrToString(file.head),
contents: arrToString(file.contents),
tail: arrToString(file.tail)
};
return map;
}, {});
}
challenge.fileName = fileName;
challenge.helpRoom = helpRoom;
challenge.order = order;
challenge.suborder = index + 1;
challenge.block = dasherize(blockName);
challenge.blockId = '' + block.id;
challenge.isBeta = challenge.isBeta || isBeta;
challenge.isComingSoon = challenge.isComingSoon || isComingSoon;
challenge.isLocked = challenge.isLocked || isLocked;
challenge.isPrivate = challenge.isPrivate || isPrivate;
challenge.time = challengeSpec.time;
challenge.superOrder = superOrder;
challenge.superBlock = superBlock
.split('-')
.map(function(word) {
return _.capitalize(word);
})
.join(' ');
challenge.required = (challenge.required || []).concat(required);
challenge.template = challenge.template || template;
return _.omit(
challenge,
[
'betaSolutions',
'betaTests',
'hints',
'MDNlinks',
'null',
'rawSolutions',
'react',
'reactRedux',
'redux',
'releasedOn',
'translations',
'type'
]
);
});
})
.flatMap(challenges => {
challenges.forEach(challenge => {
const result = validateChallenge(challenge);
if (result.error) {
console.log(result.value);
throw new Error(result.error);
}
});
return createChallenges(challenges);
});
})
.subscribe(
function(challenges) {
log('%s successfully saved', challenges[0].block);
},
function(err) { throw err; },
function() {
log('challenge seed completed');
process.exit(0);
}
);

View File

@ -0,0 +1,58 @@
{
"name": "Add and Subtract Decimals",
"order": 18,
"challenges": [
{
"id": "59a5801209a6acac5983b428",
"title": "Add and Subtract Decimal Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836409",
"title": "Mental Math to Add and Subtract Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836410",
"title": "Add and Subtract Decimals with Front-End Estimation",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836411",
"title": "Round Decimals to Estimate Sums and Differences",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,84 @@
{
"name": "Add and Subtract Fractions",
"order": 11,
"challenges": [
{
"id": "59a5801209a6acac5983b421",
"title": "Add Fractions with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836370",
"title": "Subtract Fractions with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836371",
"title": "Add and Subtract with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836372",
"title": "Add and Subtract Fractions with Common Denominators Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836373",
"title": "Add Fractions with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836374",
"title": "Subtract Fractions with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Add and Subtract Mixed Numbers",
"order": 12,
"challenges": [
{
"id": "59a5801209a6acac5983b422",
"title": "Add Mixed Numbers with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836376",
"title": "Subtract Mixed Numbers with Common Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836377",
"title": "Subtract Mixed Numbers with Different Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836378",
"title": "Add and Subtract Three Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836379",
"title": "Add and Subtract Mixed Numbers Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Additon and Subtraction",
"order": 2,
"challenges": [
{
"id": "59a5801209a6acac5983b411",
"title": "Add Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836306",
"title": "Subtract Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836307",
"title": "Estimate Whole Number Sums and Differences",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Basic Decimals",
"order": 15,
"challenges": [
{
"id": "59a5801209a6acac5983b425",
"title": "Place Value Charts and Decimals to Thousandths",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836398",
"title": "Equivalent Decimals Ending in Zero",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836399",
"title": "Decimals in Words",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836400",
"title": "Decimal Place Value",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836401",
"title": "Decimals in Expanded Form",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Basic Place Value",
"order": 1,
"challenges": [
{
"id": "59a5801209a6acac59836300",
"title": "Recognize Place Values to 10,000,000",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836301",
"title": "Greatest and Least Values of Given Digits to 10,000,000",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836303",
"title": "Higher Order Place Value and Number Placement Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836304",
"title": "Round Large Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,45 @@
{
"name": "Compare Decimals",
"order": 16,
"challenges": [
{
"id": "59a5801209a6acac5983b426",
"title": "Compare and Order Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836403",
"title": "Compare and Compose Decimals and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836404",
"title": "Compare, Order and Identify Decimal Inequalities",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Converting Decimals",
"order": 25,
"challenges": [
{
"id": "59a5801209a6acac5983b435",
"title": "Convert Decimals to Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836444",
"title": "Convert Decimals into Simplified Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836445",
"title": "Decimals as Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836446",
"title": "Compare and Order Fractions and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836447",
"title": "Convert between Decimals, Fractions, and Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,84 @@
{
"name": "Converting Fractions",
"order": 24,
"challenges": [
{
"id": "59a5801209a6acac5983b434",
"title": "Fraction and Decimal Conversion",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836438",
"title": "Convert Mixed Numbers to Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836439",
"title": "Compare Mixed Numbers and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836440",
"title": "Convert Between Fractions or Mixed Numbers and Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836441",
"title": "Add Fractions and Convert to Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836442",
"title": "Fractions as Percents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,32 @@
{
"name": "Converting Percentages",
"order": 23,
"challenges": [
{
"id": "59a5801209a6acac5983b433",
"title": "Percents as Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836436",
"title": "Percents as Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Division",
"order": 4,
"challenges": [
{
"id": "59a5801209a6acac5983b413",
"title": "Divide Two Digits by One or Two Digits Without Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836319",
"title": "Higher Order Division to 1000 by One Digit",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836320",
"title": "Divide More than Two Digits by One Digit with Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836321",
"title": "Relate Division to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836322",
"title": "Estimate Whole Number Products and Quotients",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Exponents and Roots",
"order": 7,
"challenges": [
{
"id": "59a5801209a6acac5983b417",
"title": "Exponents",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836338",
"title": "Evaluate and Compare Powers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836339",
"title": "Perfect Square Roots",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836340",
"title": "Evaluate Square Roots",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,97 @@
{
"name": "Factors",
"order": 8,
"challenges": [
{
"id": "59a5801209a6acac5983b418",
"title": "Prime and Composite Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836342",
"title": "Prime Factorization",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836343",
"title": "Identify Factor Pairs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836344",
"title": "Divisibility Rules to Find Factors",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836345",
"title": "GCF Greatest Common Factor",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836346",
"title": "Common Multiples",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836347",
"title": "LCM Least Common Multiple",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,136 @@
{
"name": "Fractions",
"order": 10,
"challenges": [
{
"id": "59a5801209a6acac5983b420",
"title": "Equivalent Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836360",
"title": "Simplify Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836361",
"title": "Simplify Fractions Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836362",
"title": "Compare Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836363",
"title": "Compare Fractions using Pictures",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836364",
"title": "Compare Fractions that have Common Numerators or Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836365",
"title": "Compare Fractions without Common Numerators or Denominators",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836366",
"title": "Compare Fractions without Common Numerators or Denominators Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836367",
"title": "Estimate and Round Fractions and Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836368",
"title": "Convert and Compare Mixed Numbers and Improper Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,149 @@
{
"name": "Integer Operations",
"order": 9,
"challenges": [
{
"id": "59a5801209a6acac5983b419",
"title": "Integers in the Real World",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836349",
"title": "Integers on a Number Line",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836350",
"title": "Absolute Value of Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836351",
"title": "Add Integers with the Same Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836352",
"title": "Add Integers with Different Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836353",
"title": "Integer Addition",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836354",
"title": "Subtract Integers with the Same Sign",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836355",
"title": "Subtract Integers with Different Signs",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836356",
"title": "Integer Subtraction",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836357",
"title": "Multiply Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836358",
"title": "Divide Integers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,71 @@
{
"name": "Long Division",
"order": 5,
"challenges": [
{
"id": "59a5801209a6acac5983b415",
"title": "Long Division Without Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836324",
"title": "Divide up to Four Digits by Two Digits with Remainders",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836325",
"title": "Groups and Remainders Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836326",
"title": "Long Division Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836327",
"title": "Divide Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,136 @@
{
"name": "Multiplication",
"order": 3,
"challenges": [
{
"id": "59a5801209a6acac5983b412",
"title": "Multiply Multiple Digits by One Digit",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836309",
"title": "Higher Order One Digit Multiplication Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836310",
"title": "Relate One Digit Number Patterns to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836311",
"title": "Multiply Numbers with the Associative Property",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836312",
"title": "Multiply Two Digits by Two or More Digits",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836313",
"title": "Multiply and Compare with Greater/Less Than",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836314",
"title": "Relate Number Patterns to Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836315",
"title": "Higher Order Multiplication Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836316",
"title": "Multiply Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836317",
"title": "Mental Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,58 @@
{
"name": "Multiply and Divide Decimals",
"order": 19,
"challenges": [
{
"id": "59a5801209a6acac5983b429",
"title": "Decimal Multiplication",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836413",
"title": "Decimal Division",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836414",
"title": "Multiply Decimals and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836415",
"title": "Estimate Products and Quotients of Decimals",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,162 @@
{
"name": "Multiply and Divide Fractions",
"order": 13,
"challenges": [
{
"id": "59a5801209a6acac5983b423",
"title": "Multiply Whole Numbers and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836381",
"title": "Multiply Two Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836382",
"title": "Multiply Three or More Fractions and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836383",
"title": "Multiply Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836384",
"title": "Multiply Mixed Numbers Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836385",
"title": "Reciprocal Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836386",
"title": "Divide Fractions and Whole Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836387",
"title": "Divide Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836388",
"title": "Divide Whole Numbers by Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836389",
"title": "Divide Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836390",
"title": "Multiply and Divide Fractions and Mixed Numbers",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836391",
"title": "Estimate Products of Whole Numbers and Fractions",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,123 @@
{
"name": "Order of Operations",
"order": 6,
"challenges": [
{
"id": "59a5801209a6acac5983b416",
"title": "Introduction to Order of Operations",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836329",
"title": "Divide and Subtract with Remainders in Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836330",
"title": "Division and Subtraction Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836331",
"title": "Higher Order Division and Subtraction Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836332",
"title": "Multiply and Add Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836333",
"title": "Multiply and Add or Subtract Word Problems",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836334",
"title": "Place Operators to Make True Statements",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836335",
"title": "Place Operators to Make True Statements that Include Parentheses",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836336",
"title": "Place Parentheses to Make True Statements",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

View File

@ -0,0 +1,110 @@
{
"name": "Percentages",
"order": 22,
"challenges": [
{
"id": "59a5801209a6acac5983b432",
"title": "Overview of Percentages",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836428",
"title": "Percent of a Number",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836429",
"title": "Simple Interest",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836430",
"title": "Percent of Change",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836431",
"title": "Percent of Increase",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836432",
"title": "Percent of Decrease",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836433",
"title": "Prices Involving Discounts",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
},
{
"id": "59a5801209a6acac59836434",
"title": "Total Bill Including Tip and Tax",
"description": [
""
],
"challengeSeed": [
""
],
"tests": [
""
]
}
]
}

Some files were not shown because too many files have changed in this diff Show More