Merge pull request #4 from FreeCodeCamp/master

Master
This commit is contained in:
Ben McMahon
2015-10-29 21:07:14 +00:00
143 changed files with 8067 additions and 4312 deletions

View File

@ -1,7 +1,7 @@
language: node_js
services:
- mongodb
node_js:
- '0.10'
- 'node'
- '1.6.4'
sudo: false

View File

@ -1,2 +1,12 @@
We're getting a lot of duplicate issues and bug reports that just aren't reporting actual bugs.
So, before you submit your issue, please read the [Help I've Found a Bug](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help-I've-Found-a-Bug) wiki page.
We welcome pull requests from Free Code Camp campers (our students) and seasoned JavaScript developers alike! Follow these steps to contribute:
1. Check our [public Waffle Board](https://waffle.io/freecodecamp/freecodecamp).
2. Pick an issue that nobody has claimed and start working on it. If your issue isn't on the board, open an issue. If you think you can fix it yourself, start working on it. Feel free to ask for help in our [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp).
3. Fork the project ([Need help with forking a project?](https://help.github.com/articles/fork-a-repo/)). You'll do all of your work on your forked copy.
4. Create a branch specific to the issue or feature you are working on. Push your work to that branch. ([Need help with branching?](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches))
5. 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/email-login` would be a branch where I fix something specific to email login.
6. 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 [Free Code Camp's JavaScript Style Guide](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Free-Code-Camp-JavaScript-Style-Guide) (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. Make sure none of your JavaScript is longer than 80 characters per line.
7. Once your code is ready, submit a [pull request](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Pull-Request-Contribute) from your branch to Free Code Camp's `staging` branch. We'll do a quick code review and give you feedback, then iterate from there. It may also be helpful to read about git [rebasing](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/git-rebase).

View File

@ -1,4 +1,4 @@
<img src="https://s3.amazonaws.com/freecodecamp/wide-social-banner.png">
![](https://s3.amazonaws.com/freecodecamp/wide-social-banner.png)
[![Throughput Graph](https://graphs.waffle.io/freecodecamp/freecodecamp/throughput.svg)](https://waffle.io/freecodecamp/freecodecamp/metrics)
@ -7,7 +7,7 @@
Welcome to Free Code Camp's open source codebase!
=======================
Free Code Camp is an open-source community of busy people who learn to code, then build projects for nonprofits.
Free Code Camp is an open-source community of busy people who learn to code and build projects for nonprofits.
Our campers (students) start by working through our free, self-paced, browser-based curriculum. Next, they build several practice projects. Finally, we pair two campers together with a stakeholder from a nonprofit organization, and help them build the solution the nonprofit has requested.
@ -15,7 +15,7 @@ Our campers (students) start by working through our free, self-paced, browser-ba
80% of our campers are over 25, and nearly a fifth of our campers are women.
This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://blog.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp).
This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We also have [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp), a [blog](http://medium.freecodecamp.com), and even a [Twitch.tv channel](http://twitch.tv/freecodecamp).
[Join our community here](http://www.freecodecamp.com/signin).
@ -24,7 +24,7 @@ This code is running live at [FreeCodeCamp.com](http://www.FreeCodeCamp.com). We
Wiki
------------
We would love your help expanding our [wiki](https://github.com/freecodecamp/freecodecamp/wiki) with more information about learning to code and getting a coding job.
We would love your help expanding our [wiki](https://github.com/freecodecamp/freecodecamp/wiki). Our goal is to become a great resource for people learning to code, building local coding communities, and applying for coding jobs.
Contributing
------------
@ -35,10 +35,9 @@ We welcome pull requests from Free Code Camp campers (our students) and seasoned
2. Pick an issue that nobody has claimed and start working on it. If your issue isn't on the board, open an issue. If you think you can fix it yourself, start working on it. Feel free to ask for help in our [Gitter](https://gitter.im/FreeCodeCamp/FreeCodeCamp).
3. Fork the project ([Need help with forking a project?](https://help.github.com/articles/fork-a-repo/)). You'll do all of your work on your forked copy.
4. Create a branch specific to the issue or feature you are working on. Push your work to that branch. ([Need help with branching?](https://github.com/Kunena/Kunena-Forum/wiki/Create-a-new-branch-with-git-and-manage-branches))
5. Name the branch something like `user-xxx` where user is your username and xxx is the issue number you are addressing.
6. 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 [AirBnB's JavaScript Style Guide](https://github.com/airbnb/javascript). Please do not ignore any linting errors, as they are meant to **help** you. Make sure none of your JavaScript is longer than 80 characters per line.
7. Once your code is ready, submit a pull request from your branch to Free Code Camp's `staging` branch. We'll do a quick code review and give you feedback, then iterate from there.
8. Once we accept one of your pull requests, one of the project owners (currently @quincylarson, @terakilobyte, and @berkeleytrue) will add you to our camper contributor group.
5. 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/email-login` would be a branch where I fix something specific to email login.
6. 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 [Free Code Camp's JavaScript Style Guide](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Free-Code-Camp-JavaScript-Style-Guide) (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. Make sure none of your JavaScript is longer than 80 characters per line.
7. Once your code is ready, submit a [pull request](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Pull-Request-Contribute) from your branch to Free Code Camp's `staging` branch. We'll do a quick code review and give you feedback, then iterate from there. It may also be helpful to read about git [rebasing](https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/git-rebase).
Prerequisites
-------------
@ -55,25 +54,28 @@ The easiest way to get started is to clone the repository:
# Get the latest snapshot
git clone --depth=1 https://github.com/freecodecamp/freecodecamp.git freecodecamp
# Change directory
cd freecodecamp
# Install NPM dependencies
npm install
# Install Gulp globally
npm install -g gulp
# Install Bower globally
npm install -g bower
# Install Bower dependencies
bower install
# Create a .env file and populate it with the necessary API keys and secrets:
touch .env
# Install Gulp globally
npm install -g gulp
```
Edit your .env file with the following API keys accordingly (if you only use email login, only the MONGOHQ_URL, SESSION_SECRET, MANDRILL_USER and MANDRILL_PASSWORD fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services.
Edit your `.env` file with the following API keys accordingly. If you only use email login, only the `MONGOHQ_URL`, `SESSION_SECRET`, `MANDRILL_USER` and `MANDRILL_PASSWORD` fields are necessary. Keep in mind if you want to use more services you'll have to get your own API keys for those services. If you only use a subset or no OAuth2 authentication methods, you may want to remove them from ```server/passport-providers.js``` - otherwise the server will complain about missing clientIDs at launch.
```
MONGOHQ_URL='mongodb://localhost:27017/freecodecamp'
FACEBOOK_ID=stuff
@ -106,26 +108,23 @@ COOKIE_SECRET='this is a secret'
PEER=stuff
DEBUG=true
```
```bash
# Start the mongo server
# Start the mongo server in a seperate terminal
mongod
# Create your mongo database.
# Type "mongo" in your terminal to access the mongo shell
use freecodecamp
# Exit the mongo shell with control + d
# Seed your database with the challenges
node seed/
# Initialize Free Code Camp
# This will seed the database for the first time.
# This command should only be run once.
npm run first-time
# start the application
gulp
```
Now navigate to your browser and open http://localhost:3001
If the app loads, congratulations - you're all set. Otherwise, let us know by opening a GitHub issue and with your error.
License
-------

View File

@ -26,6 +26,7 @@
"moment": "~2.10.2",
"angular-bootstrap": "~0.13.0",
"ramda": "~0.13.0",
"jshint": "~2.7.0"
"jshint": "~2.7.0",
"lightbox2": "~2.8.1"
}
}

File diff suppressed because one or more lines are too long

2
client/es6-shims.js Normal file
View File

@ -0,0 +1,2 @@
require('object.assign').shim();
require('es6-map/implement');

View File

@ -1,9 +1,10 @@
import unused from './es6-shims'; // eslint-disable-line
import Rx from 'rx';
import React from 'react';
import Fetchr from 'fetchr';
import debugFactory from 'debug';
import { Router } from 'react-router';
import { history } from 'react-router/lib/BrowserHistory';
import { createLocation, createHistory } from 'history';
import { hydrate } from 'thundercats';
import { Render } from 'thundercats-react';
@ -17,21 +18,29 @@ const services = new Fetchr({
});
Rx.config.longStackSupport = !!debug.enabled;
const history = createHistory();
const appLocation = createLocation(
location.pathname + location.search
);
// returns an observable
app$(history)
app$({ history, location: appLocation })
.flatMap(
({ AppCat }) => {
// instantiate the cat with service
const appCat = AppCat(null, services);
// hydrate the stores
return hydrate(appCat, catState)
.map(() => appCat);
},
({ initialState }, appCat) => ({ initialState, appCat })
// not using nextLocation at the moment but will be used for
// redirects in the future
({ nextLocation, props }, appCat) => ({ nextLocation, props, appCat })
)
.flatMap(({ initialState, appCat }) => {
.flatMap(({ props, appCat }) => {
props.history = history;
return Render(
appCat,
React.createElement(Router, initialState),
React.createElement(Router, props),
DOMContianer
);
})

24
client/less/chat.less Normal file
View File

@ -0,0 +1,24 @@
.chat-embed-main-title {
display: flex;
flex-grow: 1;
padding-left: 31px;
padding-top: 7px;
}
.gitter-chat-embed {
z-index: 100;
position: fixed;
top: 0;
left: 60%;
bottom: 0;
right: 0;
display: flex;
flex-direction: row;
transition: transform 0.3s cubic-bezier(0.16, 0.22, 0.22, 1.7);
}
.gitter-chat-embed.is-collapsed:not(.is-loading) {
transform: translateX(110%);
}

View File

@ -107,7 +107,7 @@
@border-radius-small: 3px;
//** Global color for active items (e.g., navs or dropdowns).
@component-active-color: #eee;
@component-active-color: @gray-lighter;
//** Global background color for active items (e.g., navs or dropdowns).
@component-active-bg: @brand-primary;
@ -145,26 +145,26 @@
@btn-font-weight: normal;
@btn-default-color: #333;
@btn-default-bg: #eee;
@btn-default-bg: @gray-lighter;
@btn-default-border: #ccc;
@btn-primary-color: #eee;
@btn-primary-color: @gray-lighter;
@btn-primary-bg: @brand-primary;
@btn-primary-border: darken(@btn-primary-bg, 5%);
@btn-success-color: #eee;
@btn-success-color: @gray-lighter;
@btn-success-bg: @brand-success;
@btn-success-border: darken(@btn-success-bg, 5%);
@btn-info-color: #eee;
@btn-info-color: @gray-lighter;
@btn-info-bg: @brand-info;
@btn-info-border: darken(@btn-info-bg, 5%);
@btn-warning-color: #eee;
@btn-warning-color: @gray-lighter;
@btn-warning-bg: @brand-warning;
@btn-warning-border: darken(@btn-warning-bg, 5%);
@btn-danger-color: #eee;
@btn-danger-color: @gray-lighter;
@btn-danger-bg: @brand-danger;
@btn-danger-border: darken(@btn-danger-bg, 5%);
@ -176,7 +176,7 @@
//##
//** `<input>` background color
@input-bg: #eee;
@input-bg: @gray-lighter;
//** `<input disabled>` background color
@input-bg-disabled: @gray-lighter;
@ -223,7 +223,7 @@
//## Dropdown menu container and contents.
//** Background for the dropdown menu.
@dropdown-bg: #eee;
@dropdown-bg: @gray-lighter;
//** Dropdown menu `border-color`.
@dropdown-border: rgba(0,0,0,.15);
//** Dropdown menu `border-color` **for IE8**.
@ -359,10 +359,10 @@
@navbar-default-border: darken(@navbar-default-bg, 6.5%);
// Navbar links
@navbar-default-link-color: #eee;
@navbar-default-link-color: @gray-lighter;
@navbar-default-link-hover-color: #4a2b0f;
@navbar-default-link-hover-bg: #eee;
@navbar-default-link-active-color: #eee;
@navbar-default-link-hover-bg: @gray-lighter;
@navbar-default-link-active-color: @gray-lighter;
@navbar-default-link-active-bg: darken(@navbar-default-bg, 6.5%);
@navbar-default-link-disabled-color: #ccc;
@navbar-default-link-disabled-bg: transparent;
@ -386,7 +386,7 @@
// Inverted navbar links
@navbar-inverse-link-color: @gray-light;
@navbar-inverse-link-hover-color: #eee;
@navbar-inverse-link-hover-color: @gray-lighter;
@navbar-inverse-link-hover-bg: transparent;
@navbar-inverse-link-active-color: @navbar-inverse-link-hover-color;
@navbar-inverse-link-active-bg: darken(@navbar-inverse-bg, 10%);
@ -395,12 +395,12 @@
// Inverted navbar brand label
@navbar-inverse-brand-color: @navbar-inverse-link-color;
@navbar-inverse-brand-hover-color: #eee;
@navbar-inverse-brand-hover-color: @gray-lighter;
@navbar-inverse-brand-hover-bg: transparent;
// Inverted navbar toggle
@navbar-inverse-toggle-hover-bg: #333;
@navbar-inverse-toggle-icon-bar-bg: #eee;
@navbar-inverse-toggle-icon-bar-bg: @gray-lighter;
@navbar-inverse-toggle-border-color: #333;
@ -415,7 +415,7 @@
@nav-disabled-link-color: @gray-light;
@nav-disabled-link-hover-color: @gray-light;
@nav-open-link-hover-color: #eee;
@nav-open-link-hover-color: @gray-lighter;
//== Tabs
@nav-tabs-border-color: #ddd;
@ -440,19 +440,19 @@
//##
@pagination-color: @link-color;
@pagination-bg: #eee;
@pagination-bg: @gray-lighter;
@pagination-border: #ddd;
@pagination-hover-color: @link-hover-color;
@pagination-hover-bg: @gray-lighter;
@pagination-hover-border: #ddd;
@pagination-active-color: #eee;
@pagination-active-color: @gray-lighter;
@pagination-active-bg: @brand-primary;
@pagination-active-border: @brand-primary;
@pagination-disabled-color: @gray-light;
@pagination-disabled-bg: #eee;
@pagination-disabled-bg: @gray-lighter;
@pagination-disabled-border: #ddd;
@ -511,7 +511,7 @@
//** Tooltip max width
@tooltip-max-width: 200px;
//** Tooltip text color
@tooltip-color: #eee;
@tooltip-color: @gray-lighter;
//** Tooltip background color
@tooltip-bg: #000;
@tooltip-opacity: .9;
@ -527,7 +527,7 @@
//##
//** Popover body background color
@popover-bg: #eee;
@popover-bg: @gray-lighter;
//** Popover maximum width
@popover-max-width: 276px;
//** Popover border color
@ -541,7 +541,7 @@
//** Popover arrow width
@popover-arrow-width: 10px;
//** Popover arrow color
@popover-arrow-color: #eee;
@popover-arrow-color: @gray-lighter;
@popover-arrow-color: @popover-bg;
//** Popover outer arrow width
@ -570,9 +570,9 @@
@label-danger-bg: @brand-danger;
//** Default label text color
@label-color: #eee;
@label-color: @gray-lighter;
//** Default text color of a linked label
@label-link-hover-color: #eee;
@label-link-hover-color: @gray-lighter;
//== Modals
@ -588,7 +588,7 @@
@modal-title-line-height: @line-height-base;
//** Background color of modal content area
@modal-content-bg: #eee;
@modal-content-bg: @gray-lighter;
//** Modal content border color
@modal-content-border-color: rgba(0,0,0,.2);
//** Modal content border color **for IE8**
@ -640,7 +640,7 @@
//** Background color of the whole progress component
@progress-bg: #f5f5f5;
//** Progress bar text color
@progress-bar-color: #eee;
@progress-bar-color: @gray-lighter;
//** Variable for setting rounded corners on progress bar.
@progress-border-radius: @border-radius-base;
@ -662,7 +662,7 @@
//##
//** Background color on `.list-group-item`
@list-group-bg: #eee;
@list-group-bg: @gray-lighter;
//** `.list-group-item` border color
@list-group-border: #ddd;
//** List group border radius
@ -695,7 +695,7 @@
//
//##
@panel-bg: #eee;
@panel-bg: @gray-lighter;
@panel-body-padding: 15px;
@panel-heading-padding: 10px 15px;
@panel-footer-padding: @panel-heading-padding;
@ -709,7 +709,7 @@
@panel-default-border: #ddd;
@panel-default-heading-bg: #f5f5f5;
@panel-primary-text: #eee;
@panel-primary-text: @gray-lighter;
@panel-primary-border: @brand-primary;
@panel-primary-heading-bg: @brand-primary;
@ -717,7 +717,7 @@
@panel-success-border: @state-success-border;
@panel-success-heading-bg: @state-success-bg;
@panel-info-text: #eee;
@panel-info-text: @gray-lighter;
@panel-info-border: darken(#4a2b0f, 5%);
@panel-info-heading-bg: #4a2b0f;
@ -761,15 +761,15 @@
//
//##
@badge-color: #eee;
@badge-color: @gray-lighter;
//** Linked badge text color on hover
@badge-link-hover-color: #eee;
@badge-link-hover-color: @gray-lighter;
@badge-bg: @gray-light;
//** Badge text color in active nav link
@badge-active-color: @link-color;
//** Badge background color in active nav link
@badge-active-bg: #eee;
@badge-active-bg: @gray-lighter;
@badge-font-weight: bold;
@badge-line-height: 1;
@ -798,15 +798,15 @@
@carousel-text-shadow: 0 1px 2px rgba(0,0,0,.6);
@carousel-control-color: #eee;
@carousel-control-color: @gray-lighter;
@carousel-control-width: 15%;
@carousel-control-opacity: .5;
@carousel-control-font-size: 20px;
@carousel-indicator-active-bg: #eee;
@carousel-indicator-border-color: #eee;
@carousel-indicator-active-bg: @gray-lighter;
@carousel-indicator-border-color: @gray-lighter;
@carousel-caption-color: #eee;
@carousel-caption-color: @gray-lighter;
//== Close
@ -815,7 +815,7 @@
@close-font-weight: bold;
@close-color: #000;
@close-text-shadow: 0 1px 0 #eee;
@close-text-shadow: 0 1px 0 @gray-lighter;
//== Code
@ -825,7 +825,7 @@
@code-color: #c7254e;
@code-bg: #f9f2f4;
@kbd-color: #eee;
@kbd-color: @gray-lighter;
@kbd-bg: #333;
@pre-bg: #f5f5f5;

View File

@ -37,8 +37,7 @@ html {
overflow-x: hidden;
}
input[type=checkbox]
{
input[type=checkbox] {
/* Double-sized Checkboxes */
-ms-transform: scale(2); /* IE */
-moz-transform: scale(2); /* FF */
@ -48,7 +47,7 @@ input[type=checkbox]
}
body.full-screen-body-background {
background-color: #eeeeee;
background-color: @gray-lighter;
}
@ -97,28 +96,18 @@ h1, h2, h3, h4, h5, h6, p, li {
margin-right: 5px;
}
.fa:hover {
text-decoration: none;
}
.img-center {
margin: 0 auto;
}
.three-by-three {
height: 100px;
}
.darker-background {
background-color: #dedede;
}
/**/
.btn-cta {
font-size: 40px;
}
.nonprofit-cta {
font-size: 28px;
}
.btn, .shadow {
white-space: normal;
-webkit-box-shadow: 2px 4px 1px rgba(0, 0, 0, 0.3);
@ -142,25 +131,6 @@ ul {
word-wrap: break-word;
}
.img-center {
margin:0 auto;
}
.centered-iframe {
display:block;
}
@media (min-width: 767px) {
.landing-panel-body {
padding-left: 40px;
padding-right: 40px;
}
}
.landing-panel-heading {
font-size: 40px;
}
.panel-heading {
font-size: 25px;
}
@ -175,14 +145,6 @@ ul {
font-size: 26px;
}
.five-pixel-break {
height: 5px;
}
.fifteen-pixel-break {
height: 15px;
}
.nav-height {
height: 50px;
border: none;
@ -197,51 +159,30 @@ ul {
font-size: 150px;
}
.responsive-container { position: relative; padding-bottom: 56.25%; padding-top: 30px; height: 0; overflow: hidden; }
.responsive-container iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
.positive-10 {
margin-top: 10px;
.positive-15 {
margin-top: 15px;
}
.positive-15-bottom {
margin-bottom: 15px;
}
.positive-15 {
margin-top: 15px;
.positive-10 {
margin-top: 10px;
}
.negative-45 {
margin-top: -45px;
margin-bottom: -45px;
}
.negative-55 {
margin-top: -55px;
margin-bottom: -55px;
}
.negative-10 {
margin-top: -10px;
}
.negative-28 {
margin-top: -28px;
}
.negative-35 {
margin-top: -35px;
}
.negative-30 {
margin-top: -30px;
.positive-5 {
margin-top: 5px;
}
.negative-5 {
margin-top: -5px;
}
.negative-10 {
margin-top: -10px;
}
.negative-15 {
margin-top: -15px;
}
@ -250,14 +191,35 @@ ul {
margin-top: -20px;
}
.negative-bottom-margin-30 {
.negative-28 {
margin-top: -28px;
}
.negative-30 {
margin-top: -30px;
}
.negative-30-bottom {
margin-bottom: -30px;
}
.negative-35 {
margin-top: -35px;
}
.negative-55 {
margin-top: -55px;
margin-bottom: -55px;
}
.large-p {
font-size: 24px;
}
.map-p {
font-size: 20px;
}
.large-li {
font-size: 24px;
}
@ -270,36 +232,11 @@ ul {
color: @brand-success;
}
.delay-1 {
-webkit-animation-delay: 1s;
animation-delay: 1s;
}
.delay-2 {
-webkit-animation-delay: 2s;
animation-delay: 2s;
}
.delay-4 {
-webkit-animation-delay: 4s;
animation-delay: 4s;
}
.delay-10 {
-webkit-animation-delay: 10s;
animation-delay: 10s;
}
.fast-animation {
-webkit-animation-duration: 0.5s;
animation-duration: 0.5s;
}
.slow-animation {
-webkit-animation-duration: 1.5s;
animation-duration: 1.5s;
}
.disabled {
pointer-events: none;
cursor: default;
@ -310,10 +247,6 @@ ul {
display: none;
}
.button-container {
height: 120px;
}
.nav-logo {
height: 40px;
margin-top: -10px;
@ -357,8 +290,8 @@ ul {
margin-bottom: -6px;
}
.strikethrough {
text-decoration: line-through;
.lb-container {
padding: 0px;
}
.btn-social {
@ -377,7 +310,7 @@ ul {
}
.navbar-nav > li > a {
color: #eee;
color: @gray-lighter;
&:hover {
color: #4a2b0f;
}
@ -396,11 +329,6 @@ ul {
font-size: 63px;
}
.scroll-lock {
overflow: hidden;
height: 100%;
}
.signup-btn.btn {
background-color: #ffac33;
background-image: linear-gradient(#ffcc4d, #ffac33);
@ -421,41 +349,9 @@ ul {
background-image: none;
box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.3);
}
.profile-image {
border-radius: 5px;
width: 200px;
height: 200px;
padding-left: 5px;
padding-right: 5px;
}
.team-member {
height: 420px;
}
*, *:before, *:after {box-sizing: border-box !important;}
.masonry-row {
-moz-column-width: 18em;
-webkit-column-width: 18em;
-moz-column-gap: 1em;
-webkit-column-gap:1em;
}
.masonry-block {
display: inline-block;
padding: .25rem;
width: 100%;
}
.masonry-relative {
position:relative;
display: block;
}
.next-challenge-button {
max-width: 1500px;
margin:0 auto;
*, *:before, *:after {
box-sizing: border-box !important;
}
.btn-big {
@ -505,13 +401,13 @@ thead {
}
.navbar-nav a {
color: #eee;
color: @gray-lighter;
font-size: 20px;
margin-top: -5px;
margin-bottom: -5px;
}
.navbar-toggle {
color: #eee;
color: @gray-lighter;
}
.navbar-right {
@ -525,11 +421,6 @@ thead {
padding-bottom: 10px !important;
}
.nameline {
margin-top: -5px;
font-size: 40px;
}
.public-profile-img {
height: 200px;
width: 200px;
@ -543,23 +434,6 @@ thead {
border-color: #78FA89;
}
.desktop-narrow {
@media (min-width: 767px) {
marign: 0 auto;
width: 80%;
}
}
.min650 {
min-height: 630px;
}
.portfolio-image {
height: 225px;
width: 300px;
border-radius: 5px;
}
.flat-top {
margin-top: -5px;
}
@ -573,7 +447,7 @@ thead {
}
.points-on-top {
color: #eee;
color: @gray-lighter;
font-size: 35px;
z-index: 2;
width: 60%;
@ -620,11 +494,17 @@ thead {
border-radius: 5px;
}
.story-section {
height: 500px;
}
.testimonial-copy {
font-size: 20px;
text-align: center;
text-align: justify;
font-size: 18px !important;
margin-left: 20px;
margin-right: 20px;
@media (min-width: 991px) and (max-width: 1199px) {
height: 120px;
height: 140px;
}
@media (min-width: 1200px) {
height: 90px;
@ -642,7 +522,7 @@ thead {
.challenge-list-header {
background-color: #215f1e;
color: #eee;
color: @gray-lighter;
font-size: 36px;
text-align: center;
margin-bottom: -30px;
@ -650,19 +530,8 @@ thead {
padding-left: 50px;
}
.all-list-header {
background-color: #4A2B0F;
color: #eee;
font-size: 36px;
text-align: center;
margin-bottom: -30px;
border-radius: 5px 5px 0px 0px;
padding-left: 50px;
}
.closing-x {
color: #eee;
color: @gray-lighter;
font-size: 50px;
text-align: right;
}
@ -678,7 +547,7 @@ thead {
position: absolute;
a {
font-size: 20px;
color: #eee;
color: @gray-lighter;
margin-left: 0px;
margin-right: 0px;
padding-left: 10px;
@ -687,7 +556,7 @@ thead {
padding-bottom: 12px;
&:hover {
color: #4a2b0f;
background-color: #eee;
background-color: @gray-lighter;
text-decoration: none;
}
}
@ -702,19 +571,6 @@ thead {
font-size: 15px;
}
.jquery-exercises-well {
text-align: left;
height: 200px;
}
#exercise-directory {
font-size: 20px;
}
#current-exercise {
text-size: 250px;
}
.bonfire-instructions {
margin-bottom: 5px;
}
@ -764,16 +620,13 @@ form.code span {
.test-output {
font-size: 15px;
font-family: "Ubuntu Mono";
margin-top: 8px;
}
#mainEditorPanel .panel-body {
padding-bottom: 0px;
}
.panel-bonfire {
height: 100%
}
div.CodeMirror-scroll {
padding-bottom: 30px;
}
@ -812,11 +665,6 @@ iframe.iphone {
}
}
.nonprofit-help-select-text-height {
font-size: 40px;
padding-top: 20px;
}
// To adjust right margin, negative values bring the image closer to the edge of the screen
.iphone-position {
position: absolute;
@ -829,25 +677,6 @@ iframe.iphone {
min-height: 650px;
}
// This is used to give icons text for screen readers to read out, without needing the text to actually appear.
.icon-lock{
font-size: 0px;
}
.stats-text {
font-size: 26px;
line-height: 150%;
}
.github-and-twitter-button-text {
padding-top: 10px;
}
.gitter-imbed {
height: 100%;
margin-bottom: 50px;
}
.btn-primary-ghost {
background: transparent;
color: @brand-primary;
@ -918,38 +747,11 @@ iframe.iphone {
font-size: 18px;
}
.tight-h3 {
margin-top: -4px;
margin-bottom: -4px;
}
.story-list {
padding-bottom: 30px;
margin-bottom: 30px;
}
.big-ion-up-arrow {
font-size: 45px;
margin-top: -10px;
margin-bottom: -15px;
text-align: center;
}
.big-ion-up-arrow #upvote, #reply-to-main-post {
cursor: pointer;
}
.story-up-votes {
padding-top: 0px;
margin-left: -5px;
text-align: center;
}
.img-story-post {
max-width: 110px;
max-height: 110px;
}
.button-spacer {
padding: 5px 0 2px 0;
}
@ -1057,11 +859,7 @@ hr {
}
.cal-heatmap-container {
background-color: #EEEEEE;
}
.checkbox-table label {
margin-left: 10px;
background-color: @gray-lighter;
}
.interested-camper-image {
@ -1070,16 +868,6 @@ hr {
padding: 5px;
}
.svg-challenge-map {
fill: #333;
height: 40px;
}
.news-number {
font-size: 30px;
text-align: center;
}
.mobile-story-image {
border-radius: 5px;
width: 100%;
@ -1101,10 +889,6 @@ hr {
opacity: 0.5;
}
.same-line {
display: inline-block;
}
.padded-ionic-icon {
padding-top: 5px;
}
@ -1126,6 +910,10 @@ hr {
color: @gray-light;
}
code {
padding: 0;
}
@media only screen and (min-width: 993px) {
.iframe-scroll {
position: fixed !important;
@ -1142,10 +930,6 @@ hr {
// Calculator styles
.initially-hidden {
display: none;
}
.chart rect {
fill: steelblue;
}
@ -1171,6 +955,11 @@ hr {
margin: 0!important;
}
// gitter chat
.gitter-chat-embed {
z-index: 20000 !important;
}
//uncomment this to see the dimensions of all elements outlined in red
//* {
// border-color: red;
@ -1278,3 +1067,5 @@ hr {
transform: rotate(0deg);
}
}
@import "chat.less";

View File

@ -1,14 +1,154 @@
var main = window.main || {};
main.mapShareKey = 'map-shares';
main.ga = window.ga || function() {};
main = (function(main) {
// should be set before gitter script loads
((window.gitter = {}).chat = {}).options = {
disableDefaultChat: true
};
// wait for sidecar to load
main.chat = {};
main.chat.isOpen = false;
main.chat.createHelpChat = function createHelpChat() {
throw new Error('Sidecar chat has not initialized');
};
document.addEventListener('gitter-sidecar-ready', function(e) {
main.chat.GitterChat = e.detail.Chat;
main.chat.createHelpChat = function(room, helpChatBtnClass, roomTitle) {
roomTitle = roomTitle || 'Waypoint Help';
$('body').append(
'<aside id="chat-embed-help" class="gitter-chat-embed is-collapsed" />'
);
main.chat.helpChat = new main.chat.GitterChat({
room: room,
activationElement: false,
targetElement: $('#chat-embed-help')
});
$(helpChatBtnClass).on('click', function() {
// is button already pressed?
// no? open chat
// yes? close chat
var shouldChatBeOpen = !$(this).hasClass('active');
main.chat.helpChat.toggleChat(shouldChatBeOpen);
if (shouldChatBeOpen) {
$(helpChatBtnClass).addClass('active');
}
});
var helpTitleAdd = false;
$('#chat-embed-help').on('gitter-chat-toggle', function(e) {
var shouldButtonBePressed = !!e.originalEvent.detail.state;
if (!helpTitleAdd) {
helpTitleAdd = true;
$('#chat-embed-help > .gitter-chat-embed-action-bar').prepend(
'<div class="chat-embed-main-title">' +
'<span>' +
roomTitle +
'</span>' +
'</div>'
);
}
if (shouldButtonBePressed) {
return $(helpChatBtnClass).addClass('active');
}
return $(helpChatBtnClass).removeClass('active');
});
};
$('body').append(
'<aside id="chat-embed-main" class="gitter-chat-embed is-collapsed" />'
);
main.chat.mainChat = new main.chat.GitterChat({
room: 'freecodecamp/freecodecamp',
activationElement: false,
targetElement: $('#chat-embed-main')
});
var mainChatTitleAdded = false;
$('#chat-embed-main').on('gitter-chat-toggle', function() {
if (mainChatTitleAdded) {
return null;
}
mainChatTitleAdded = true;
$('#chat-embed-main > .gitter-chat-embed-action-bar').prepend(
'<div class="chat-embed-main-title">' +
'<span>Free Code Camp\'s Main Chat</span>' +
'</div>'
);
});
$('#nav-chat-btn').on('click', function() {
if (!main.chat.isOpen) {
main.chat.mainChat.toggleChat(true);
}
});
});
return main;
}(main));
var lastCompleted = typeof lastCompleted !== 'undefined' ?
lastCompleted :
'';
function getMapShares() {
var alreadyShared = JSON.parse(
localStorage.getItem(main.mapShareKey) ||
'[]'
);
if (!alreadyShared || !Array.isArray(alreadyShared)) {
localStorage.setItem(main.mapShareKey, JSON.stringify([]));
alreadyShared = [];
}
return alreadyShared;
}
function setMapShare(id) {
var alreadyShared = getMapShares();
var found = false;
alreadyShared.forEach(function(_id) {
if (_id === id) {
found = true;
}
});
if (!found) {
alreadyShared.push(id);
}
localStorage.setItem(main.mapShareKey, JSON.stringify(alreadyShared));
return alreadyShared;
}
$(document).ready(function() {
var challengeName = typeof challengeName !== undefined ? challengeName : 'Untitled';
var challengeName = typeof challengeName !== 'undefined' ?
challengeName :
'';
if (challengeName) {
ga('send', 'event', 'Challenge', 'load', challengeName);
}
$(document).ready(function() {
if (typeof editor !== 'undefined') {
$('#reset-button').on('click', resetEditor);
}
});
var CSRF_HEADER = 'X-CSRF-Token';
@ -66,10 +206,65 @@ $(document).ready(function() {
}, 200);
});
$('#search-issue').unbind('click');
$('#search-issue').on('click', function() {
var queryIssue = window.location.href.toString();
window.open('https://github.com/FreeCodeCamp/FreeCodeCamp/issues?q=' +
'is:issue is:all ' + (challenge_Name || challengeName) + ' OR ' +
queryIssue.substr(queryIssue.lastIndexOf('challenges/') + 11)
.replace('/', ''), '_blank');
});
$('#help-ive-found-a-bug-wiki-article').unbind('click');
$('#help-ive-found-a-bug-wiki-article').on('click', function() {
window.open("https://github.com/FreeCodeCamp/FreeCodeCamp/wiki/Help-I've-Found-a-Bug", '_blank');
});
$('#report-issue').unbind('click');
$('#report-issue').on('click', function() {
var textMessage = [
'Challenge [',
(challenge_Name || challengeName || window.location.href),
'](',
window.location.href,
') has an issue.\n',
'User Agent is: <code>',
navigator.userAgent,
'</code>.\n',
'Please describe how to reproduce this issue, and include ',
'links to screenshots if possible.\n\n'
].join('');
if (typeof editor !== 'undefined' && editor.getValue().trim()) {
var type;
switch (challengeType) {
case challengeTypes.HTML_CSS_JQ:
type = 'html';
break;
case challengeTypes.JAVASCRIPT:
case challengeTypes.BONFIRE:
type = 'javascript';
break;
default:
type = '';
}
textMessage += [
'My code:\n```',
type,
'\n',
editor.getValue(),
'\n```\n\n'
].join('');
}
textMessage = encodeURIComponent(textMessage);
$('#issue-modal').modal('hide');
window.open('https://github.com/freecodecamp/freecodecamp/issues/new?&body=Challenge '+ window.location.href +' has an issue. Please describe how to reproduce it, and include links to screenshots if possible.', '_blank')
window.open(
'https://github.com/freecodecamp/freecodecamp/issues/new?&body=' +
textMessage, '_blank'
);
});
$('#completed-courseware').unbind('click');
@ -125,7 +320,7 @@ $(document).ready(function() {
}).success(
function(res) {
if (res) {
window.location.href = '/challenges/next-challenge';
window.location.href = '/challenges/next-challenge?id=' + challenge_Id;
}
}).fail(
function() {
@ -148,7 +343,7 @@ $(document).ready(function() {
}
}).success(
function() {
window.location.href = '/challenges/next-challenge';
window.location.href = '/challenges/next-challenge?id=' + challenge_Id;
}).fail(
function() {
window.location.href = '/challenges';
@ -171,25 +366,19 @@ $(document).ready(function() {
verified: false
}
}).success(function() {
window.location.href = '/challenges/next-challenge';
window.location.href = '/challenges/next-challenge?id=' + challenge_Id;
}).fail(function() {
window.location.replace(window.location.href);
});
break;
case challengeTypes.BONFIRE:
window.location.href = '/challenges/next-challenge';
window.location.href = '/challenges/next-challenge?id=' + challenge_Id;
default:
break;
}
}
});
$('.next-challenge-button').unbind('click');
$('.next-challenge-button').on('click', function() {
l = location.pathname.split('/');
window.location = '/challenges/' + (parseInt(l[l.length - 1]) + 1);
});
$('#complete-courseware-dialog').on('hidden.bs.modal', function() {
editor.focus();
});
@ -333,6 +522,41 @@ $(document).ready(function() {
}
}, false);
}
// map sharing
var alreadyShared = getMapShares();
if (lastCompleted && alreadyShared.indexOf(lastCompleted) === -1) {
$('div[id="' + lastCompleted + '"]')
.parent()
.parent()
.removeClass('hidden');
}
// on map view
$('.map-challenge-block-share').on('click', function(e) {
e.preventDefault();
var challengeBlockName = $(this).children().attr('id');
var challengeBlockEscapedName = challengeBlockName.replace(/\s/, '%20');
var username = typeof window.username !== 'undefined' ?
window.username :
'';
var link = 'https://www.facebook.com/dialog/feed?' +
'app_id=1644598365767721' +
'&display=page&' +
'caption=I%20just%20completed%20the%20' +
challengeBlockEscapedName +
'%20section%20on%20Free%20Code%20Camp%2E' +
'&link=http%3A%2F%2Ffreecodecamp%2Ecom%2F' +
username +
'&redirect_uri=http%3A%2F%2Ffreecodecamp%2Ecom%2Fmap';
setMapShare(challengeBlockName);
main.ga('send', 'event', 'FB_LINK', 'SHARE', 'Facebook map share');
window.location.href = link;
});
});
function defCheck(a){

View File

@ -1,18 +1,17 @@
import Rx from 'rx';
import assign from 'object.assign';
import { Router } from 'react-router';
import { match } from 'react-router';
import App from './App.jsx';
import AppCat from './Cat';
import childRoutes from './routes';
const router$ = Rx.Observable.fromNodeCallback(Router.run, Router);
const route$ = Rx.Observable.fromNodeCallback(match);
const routes = assign({ components: App }, childRoutes);
const routes = Object.assign({ components: App }, childRoutes);
export default function app$(location) {
return router$(routes, location)
.map(([initialState, transistion]) => {
return { initialState, transistion, AppCat };
export default function app$({ location, history }) {
return route$({ routes, location, history })
.map(([nextLocation, props]) => {
return { nextLocation, props, AppCat };
});
}

View File

@ -2,7 +2,7 @@
{
"className": "ion-speakerphone",
"content": " Blog ",
"href": "http://blog.freecodecamp.com",
"href": "http://medium.freecodecamp.com",
"target": "_blank"
},
{

View File

@ -8,13 +8,17 @@ const initValue = {
points: 0
};
export default Store(initValue)
.refs({ displayName: 'AppStore' })
.init(({ instance: appStore, args: [cat] }) => {
export default Store({
refs: {
displayName: 'AppStore',
value: initValue
},
init({ instance: appStore, args: [cat] }) {
const { setUser, setTitle } = cat.getActions('appActions');
const register = createRegistrar(appStore);
register(setter(fromMany(setUser, setTitle)));
return appStore;
}
});

View File

@ -1 +1 @@
This folder contains things relative to the bonfires screens
This folder contains things relative to the bonfires' screens

View File

@ -1,6 +1,6 @@
import React, { PropTypes } from 'react';
import { Button, Col, Row, Panel } from 'react-bootstrap';
import { Navigation } from 'react-router';
import { History } from 'react-router';
import Vimeo from 'react-vimeo';
import debugFactory from 'debug';
@ -8,7 +8,7 @@ const debug = debugFactory('freecc:hikes');
export default React.createClass({
displayName: 'Lecture',
mixins: [Navigation],
mixins: [History],
propTypes: {
currentHike: PropTypes.object,
@ -20,7 +20,7 @@ export default React.createClass({
handleFinish() {
debug('loading questions');
const { dashedName } = this.props.params;
this.transitionTo(`/hikes/${dashedName}/questions/1`);
this.history.pushState(null, `/hikes/${dashedName}/questions/1`);
},
renderTranscript(transcript, dashedName) {

View File

@ -1,6 +1,6 @@
import React, { PropTypes } from 'react';
import { Spring } from 'react-motion';
import { Navigation, TransitionHook } from 'react-router';
import { History, Lifecycle } from 'react-router';
import debugFactory from 'debug';
import {
Button,
@ -19,8 +19,8 @@ export default React.createClass({
displayName: 'Question',
mixins: [
Navigation,
TransitionHook
History,
Lifecycle
],
propTypes: {
@ -150,7 +150,8 @@ export default React.createClass({
postJSON$('/completed-challenge', { id, name }).subscribeOnCompleted(() => {
if (tests[nextQuestionIndex]) {
return this.transitionTo(
return this.history.pushState(
null,
`/hikes/${ dashedName }/questions/${ nextQuestionIndex + 1 }`
);
}
@ -168,13 +169,13 @@ export default React.createClass({
}, null);
if (nextHike) {
return this.transitionTo(`/hikes/${ nextHike.dashedName }`);
return this.history.pushState(null, `/hikes/${ nextHike.dashedName }`);
}
debug(
'next Hike was not found, currentHike %s',
currentHike.dashedName
);
this.transitionTo('/hikes');
this.history.pushState(null, '/hikes');
});
},

View File

@ -1,5 +1,4 @@
import { Actions } from 'thundercats';
import assign from 'object.assign';
import debugFactory from 'debug';
const debug = debugFactory('freecc:hikes:actions');
@ -45,7 +44,7 @@ export default Actions({
dashedName,
oldState.currentHike
);
return assign({}, oldState, { currentHike });
return Object.assign({}, oldState, { currentHike });
}
});
}

View File

@ -5,12 +5,16 @@ const initialValue = {
currentHike: {}
};
export default Store(initialValue)
.refs({ displayName: 'HikesStore'})
.init(({ instance: hikeStore, args: [cat] }) => {
export default Store({
refs: {
displayName: 'HikesStore',
value: initialValue
},
init({ instance: hikeStore, args: [cat] }) {
let { setHikes } = cat.getActions('hikesActions');
hikeStore.register(setHikes);
return hikeStore;
}
});

View File

@ -0,0 +1,43 @@
import React, { PropTypes } from 'react';
import { History } from 'react-router';
import { Button, Modal } from 'react-bootstrap';
export default React.createClass({
displayName: 'CreateJobsModal',
propTypes: {
onHide: PropTypes.func,
showModal: PropTypes.bool
},
mixins: [History],
goToNewJob(onHide) {
onHide();
this.history.pushState(null, '/jobs/new');
},
render() {
const {
showModal,
onHide
} = this.props;
return (
<Modal
onHide={ onHide }
show={ showModal }>
<Modal.Body>
<h4>Welcome to Free Code Camp's board</h4>
<p>We post jobs specifically target to our junior developers.</p>
<Button
block={ true }
className='signup-btn'
onClick={ () => this.goToNewJob(onHide) }>
Post a Job
</Button>
</Modal.Body>
</Modal>
);
}
});

View File

@ -1,23 +1,43 @@
import React, { cloneElement, PropTypes } from 'react';
import { contain } from 'thundercats-react';
import { History } from 'react-router';
import { Button, Jumbotron, Row } from 'react-bootstrap';
import CreateJobModal from './CreateJobModal.jsx';
import ListJobs from './List.jsx';
export default contain(
{
store: 'jobsStore',
fetchAction: 'jobActions.getJobs'
fetchAction: 'jobActions.getJobs',
actions: 'jobActions'
},
React.createClass({
displayName: 'Jobs',
mixins: [History],
propTypes: {
children: PropTypes.element,
jobs: PropTypes.array
jobActions: PropTypes.object,
jobs: PropTypes.array,
showModal: PropTypes.bool
},
renderList(jobs) {
handleJobClick(id) {
const { jobActions } = this.props;
if (!id) {
return null;
}
jobActions.findJob(id);
this.history.pushState(null, `/jobs/${id}`);
},
renderList(handleJobClick, jobs) {
return (
<ListJobs jobs={ jobs }/>
<ListJobs
handleClick={ handleJobClick }
jobs={ jobs }/>
);
},
@ -32,7 +52,12 @@ export default contain(
},
render() {
const { children, jobs } = this.props;
const {
children,
jobs,
showModal,
jobActions
} = this.props;
return (
<div>
@ -46,15 +71,19 @@ export default contain(
</p>
<Button
bsSize='large'
className='signup-btn'>
className='signup-btn'
onClick={ jobActions.openModal }>
Try the first month 20% off!
</Button>
</Jumbotron>
</Row>
<Row>
{ this.renderChild(children, jobs) ||
this.renderList(jobs) }
this.renderList(this.handleJobClick, jobs) }
</Row>
<CreateJobModal
onHide={ jobActions.closeModal }
showModal={ showModal } />
</div>
);
}

View File

@ -1,29 +1,28 @@
import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react';
import { PanelGroup, Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
export default contain(
{
},
React.createClass({
export default React.createClass({
displayName: 'ListJobs',
propTypes: {
handleClick: PropTypes.func,
jobs: PropTypes.array
},
renderJobs(jobs =[]) {
renderJobs(handleClick, jobs =[]) {
const thumbnailStyle = {
backgroundColor: 'white',
maxHeight: '100px',
maxWidth: '100px'
};
return jobs.map((
{
id,
company,
position,
isHighlighted,
description,
logo,
city,
@ -46,13 +45,15 @@ export default contain(
);
return (
<Panel
bsStyle={ isHighlighted ? 'warning' : 'default' }
collapsible={ true }
eventKey={ index }
header={ header }
key={ id }>
<Well>
<Thumbnail
alt='200x200' src={ logo }
alt={ company + 'company logo' }
src={ logo }
style={ thumbnailStyle } />
<Panel>
Position: { position }
@ -62,7 +63,7 @@ export default contain(
<br />
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
</Panel>
<p>{ description }</p>
<p onClick={ () => handleClick(id) }>{ description }</p>
</Well>
</Panel>
);
@ -70,12 +71,15 @@ export default contain(
},
render() {
const { jobs } = this.props;
const {
handleClick,
jobs
} = this.props;
return (
<PanelGroup>
{ this.renderJobs(jobs) }
{ this.renderJobs(handleClick, jobs) }
</PanelGroup>
);
}
})
);
});

View File

@ -0,0 +1,319 @@
import React, { PropTypes } from 'react';
import { History } from 'react-router';
import { contain } from 'thundercats-react';
import debugFactory from 'debug';
import { getDefaults } from '../utils';
import {
inHTMLData,
uriInSingleQuotedAttr
} from 'xss-filters';
import {
Button,
Col,
Input,
Row,
Well
} from 'react-bootstrap';
import {
isAscii,
isEmail,
isMobilePhone,
isURL
} from 'validator';
const debug = debugFactory('freecc:jobs:newForm');
const checkValidity = [
'position',
'locale',
'description',
'email',
'phone',
'url',
'logo',
'name',
'highlight'
];
function formatValue(value, validator, type = 'string') {
const formated = getDefaults(type);
if (validator && type === 'string') {
formated.valid = validator(value);
}
if (value) {
formated.value = value;
formated.bsStyle = formated.valid ? 'success' : 'error';
}
return formated;
}
function isValidURL(data) {
return isURL(data, { 'require_protocol': true });
}
function isValidPhone(data) {
return isMobilePhone(data, 'en-US');
}
export default contain({
actions: 'jobActions',
store: 'jobsStore',
map({ form = {} }) {
const {
position,
locale,
description,
email,
phone,
url,
logo,
name,
highlight
} = form;
return {
position: formatValue(position, isAscii),
locale: formatValue(locale, isAscii),
description: formatValue(description, isAscii),
email: formatValue(email, isEmail),
phone: formatValue(phone, isValidPhone),
url: formatValue(url, isValidURL),
logo: formatValue(logo, isValidURL),
name: formatValue(name, isAscii),
highlight: formatValue(highlight, null, 'bool')
};
},
subscribeOnWillMount() {
return typeof window !== 'undefined';
}
},
React.createClass({
displayName: 'NewJob',
propTypes: {
jobActions: PropTypes.object,
position: PropTypes.object,
locale: PropTypes.object,
description: PropTypes.object,
email: PropTypes.object,
phone: PropTypes.object,
url: PropTypes.object,
logo: PropTypes.object,
name: PropTypes.object,
highlight: PropTypes.object
},
mixins: [History],
handleSubmit(e) {
e.preventDefault();
const props = this.props;
let valid = true;
checkValidity.forEach((prop) => {
// if value exist, check if it is valid
if (props[prop].value && props[prop].type !== 'boolean') {
valid = valid && !!props[prop].valid;
}
});
if (!valid) {
debug('form not valid');
return;
}
const {
position,
locale,
description,
email,
phone,
url,
logo,
name,
highlight,
jobActions
} = this.props;
// sanitize user output
const jobValues = {
position: inHTMLData(position.value),
location: inHTMLData(locale.value),
description: inHTMLData(description.value),
email: inHTMLData(email.value),
phone: inHTMLData(phone.value),
url: uriInSingleQuotedAttr(url.value),
logo: uriInSingleQuotedAttr(logo.value),
name: inHTMLData(name.value),
highlight: !!highlight.value
};
const job = Object.keys(jobValues).reduce((accu, prop) => {
if (jobValues[prop]) {
accu[prop] = jobValues[prop];
}
return accu;
}, {});
job.postedOn = new Date();
debug('job sanitized', job);
jobActions.saveForm(job);
this.history.pushState(null, '/jobs/new/preview');
},
componentDidMount() {
const { jobActions } = this.props;
jobActions.getSavedForm();
},
handleChange(name, { target: { value } }) {
const { jobActions: { handleForm } } = this.props;
handleForm({ [name]: value });
},
render() {
const {
position,
locale,
description,
email,
phone,
url,
logo,
name,
highlight,
jobActions: { handleForm }
} = this.props;
const { handleChange } = this;
const labelClass = 'col-sm-offset-1 col-sm-2';
const inputClass = 'col-sm-6';
return (
<div>
<Row>
<Col>
<Well className='text-center'>
<h1>Create Your Job Post</h1>
<form
className='form-horizontal'
onSubmit={ this.handleSubmit }>
<div className='spacer'>
<h2>Job Information</h2>
</div>
<Input
bsStyle={ position.bsStyle }
label='Position'
labelClassName={ labelClass }
onChange={ (e) => handleChange('position', e) }
placeholder='Position'
type='text'
value={ position.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ locale.bsStyle }
label='Location'
labelClassName={ labelClass }
onChange={ (e) => handleChange('locale', e) }
placeholder='Location'
type='text'
value={ locale.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ description.bsStyle }
label='Description'
labelClassName={ labelClass }
onChange={ (e) => handleChange('description', e) }
placeholder='Description'
rows='10'
type='textarea'
value={ description.value }
wrapperClassName={ inputClass } />
<div className='divider'>
<h2>Company Information</h2>
</div>
<Input
bsStyle={ name.bsStyle }
label='Company Name'
labelClassName={ labelClass }
onChange={ (e) => handleChange('name', e) }
placeholder='Foo, INC'
type='text'
value={ name.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ email.bsStyle }
label='Email'
labelClassName={ labelClass }
onChange={ (e) => handleChange('email', e) }
placeholder='Email'
type='email'
value={ email.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ phone.bsStyle }
label='Phone'
labelClassName={ labelClass }
onChange={ (e) => handleChange('phone', e) }
placeholder='555-123-1234'
type='tel'
value={ phone.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ url.bsStyle }
label='URL'
labelClassName={ labelClass }
onChange={ (e) => handleChange('url', e) }
placeholder='http://freecatphotoapp.com'
type='url'
value={ url.value }
wrapperClassName={ inputClass } />
<Input
bsStyle={ logo.bsStyle }
label='Logo'
labelClassName={ labelClass }
onChange={ (e) => handleChange('logo', e) }
placeholder='http://freecatphotoapp.com/logo.png'
type='url'
value={ logo.value }
wrapperClassName={ inputClass } />
<div className='divider'>
<h2>Make it stand out</h2>
</div>
<Input
checked={ highlight.value }
label='Highlight your ad'
labelClassName={ 'col-sm-offset-1 col-sm-6'}
onChange={
({ target: { checked } }) => handleForm({
highlight: !!checked
})
}
type='checkbox' />
<div className='spacer' />
<Row>
<Col
lg={ 6 }
lgOffset={ 3 }>
<Button
block={ true }
bsSize='large'
bsStyle='primary'
type='submit'>
Preview My Ad
</Button>
</Col>
</Row>
</form>
</Well>
</Col>
</Row>
</div>
);
}
})
);

View File

@ -0,0 +1,14 @@
// import React, { PropTypes } from 'react';
import { contain } from 'thundercats-react';
import ShowJob from './ShowJob.jsx';
export default contain(
{
store: 'JobsStore',
actions: 'JobActions',
map({ form: job = {} }) {
return { job };
}
},
ShowJob
);

View File

@ -1,59 +1,24 @@
import React, { PropTypes } from 'react';
import { Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
import { contain } from 'thundercats-react';
import ShowJob from './ShowJob.jsx';
const thumbnailStyle = {
backgroundColor: 'white',
maxHeight: '100px',
maxWidth: '100px'
export default contain(
{
store: 'jobsStore',
fetchAction: 'jobActions.getJob',
map({ currentJob }) {
return { job: currentJob };
},
getPayload({ params: { id }, job = {} }) {
return {
id,
isPrimed: job.id === id
};
export default React.createClass({
displayName: 'ShowJob',
propTypes: {
job: PropTypes.object
},
renderHeader({ company, position }) {
return (
<div>
<h4 style={{ display: 'inline-block' }}>{ company }</h4>
<h5
className='pull-right hidden-xs hidden-md'
style={{ display: 'inline-block' }}>
{ position }
</h5>
</div>
);
},
render() {
const { job } = this.props;
const {
logo,
position,
city,
state,
email,
phone,
postedOn,
description
} = job;
return (
<Well>
<Thumbnail
alt='200x200' src={ logo }
style={ thumbnailStyle } />
<Panel>
Position: { position }
Location: { city }, { state }
<br />
Contact: { email || phone || 'N/A' }
<br />
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
</Panel>
<p>{ description }</p>
</Well>
);
// using es6 destructuring
shouldContainerFetch({ job = {} }, { params: { id } }
) {
return job.id !== id;
}
});
},
ShowJob
);

View File

@ -0,0 +1,67 @@
import React, { PropTypes } from 'react';
import { Row, Thumbnail, Panel, Well } from 'react-bootstrap';
import moment from 'moment';
const thumbnailStyle = {
backgroundColor: 'white',
maxHeight: '100px',
maxWidth: '100px'
};
export default React.createClass({
displayName: 'ShowJob',
propTypes: {
job: PropTypes.object,
params: PropTypes.object
},
renderHeader({ company, position }) {
return (
<div>
<h4 style={{ display: 'inline-block' }}>{ company }</h4>
<h5
className='pull-right hidden-xs hidden-md'
style={{ display: 'inline-block' }}>
{ position }
</h5>
</div>
);
},
render() {
const { job = {} } = this.props;
const {
logo,
position,
city,
company,
state,
email,
phone,
postedOn,
description
} = job;
return (
<div>
<Row>
<Well>
<Thumbnail
alt={ company + 'company logo' }
src={ logo }
style={ thumbnailStyle } />
<Panel>
Position: { position }
Location: { city }, { state }
<br />
Contact: { email || phone || 'N/A' }
<br />
Posted On: { moment(postedOn).format('MMMM Do, YYYY') }
</Panel>
<p>{ description }</p>
</Well>
</Row>
</div>
);
}
});

View File

@ -1,27 +1,104 @@
import { Actions } from 'thundercats';
import store from 'store';
import debugFactory from 'debug';
const debug = debugFactory('freecc:jobs:actions');
const assign = Object.assign;
export default Actions({
setJobs: null,
getJob(id) {
return { id };
// findJob assumes that the job is already in the list of jobs
findJob(id) {
return oldState => {
const { currentJob = {}, jobs = [] } = oldState;
// currentJob already set
// do nothing
if (currentJob.id === id) {
return null;
}
const foundJob = jobs.reduce((newJob, job) => {
if (job.id === id) {
return job;
}
return newJob;
}, null);
// if no job found this will be null which is a op noop
return foundJob ?
assign({}, oldState, { currentJob: foundJob }) :
null;
};
},
setError: null,
getJob: null,
getJobs(params) {
return { params };
},
openModal() {
return { showModal: true };
},
closeModal() {
return { showModal: false };
},
handleForm(value) {
return {
transform(oldState) {
const { form } = oldState;
const newState = assign({}, oldState);
newState.form = assign(
{},
form,
value
);
return newState;
}
};
},
saveForm: null,
getSavedForm: null,
setForm(form) {
return { form };
}
})
.refs({ displayName: 'JobActions' })
.init(({ instance: jobActions, args: [services] }) => {
jobActions.getJobs.subscribe(() => {
services.read('job', null, null, (err, jobs) => {
services.read('jobs', null, null, (err, jobs) => {
if (err) {
debug('job services experienced an issue', err);
jobActions.setJobs({ jobs: [] });
return jobActions.setError({ err });
}
jobActions.setJobs({ jobs });
});
});
jobActions.getJob.subscribe(({ id, isPrimed }) => {
// job is already set, do nothing.
if (isPrimed) {
debug('job is primed');
return;
}
services.read('jobs', { id }, null, (err, job) => {
if (err) {
debug('job services experienced an issue', err);
return jobActions.setError({ err });
}
if (job) {
jobActions.setJobs({ currentJob: job });
}
jobActions.setJobs({});
});
});
jobActions.saveForm.subscribe((form) => {
store.set('newJob', form);
});
jobActions.getSavedForm.subscribe(() => {
const job = store.get('newJob');
if (job && !Array.isArray(job) && typeof job === 'object') {
jobActions.setForm(job);
}
});
return jobActions;
});

View File

@ -1,10 +1,34 @@
import { Store } from 'thundercats';
const { setter } = Store;
const {
createRegistrar,
setter,
transformer
} = Store;
export default Store()
.refs({ displayName: 'JobsStore' })
.init(({ instance: jobsStore, args: [cat] }) => {
let jobActions = cat.getActions('JobActions');
jobsStore.register(setter(jobActions.setJobs));
export default Store({
refs: {
displayName: 'JobsStore',
value: { showModal: false }
},
init({ instance: jobsStore, args: [cat] }) {
const {
setJobs,
findJob,
setError,
openModal,
closeModal,
handleForm,
setForm
} = cat.getActions('JobActions');
const register = createRegistrar(jobsStore);
register(setter(setJobs));
register(setter(setError));
register(setter(openModal));
register(setter(closeModal));
register(setter(setForm));
register(transformer(findJob));
register(handleForm);
}
});

View File

@ -1,14 +1,26 @@
import Jobs from './components/Jobs.jsx';
import NewJob from './components/NewJob.jsx';
import Show from './components/Show.jsx';
import Preview from './components/Preview.jsx';
/*
* show: /jobs
* showOne: /jobs/:id
* edit /jobs/:id
* delete /jobs/:id
* createOne /jobs/new
* index: /jobs list jobs
* show: /jobs/:id show one job
* create /jobs/new create a new job
*/
export default {
path: 'jobs',
childRoutes: [{
path: '/jobs',
component: Jobs
}, {
path: 'jobs/new',
component: NewJob
}, {
path: 'jobs/new/preview',
component: Preview
}, {
path: 'jobs/:id',
component: Show
}]
};

View File

@ -0,0 +1,22 @@
const defaults = {
'string': {
value: '',
valid: false,
pristine: true,
type: 'string'
},
bool: {
value: false,
type: 'boolean'
}
};
export function getDefaults(type, value) {
if (!type) {
return defaults['string'];
}
if (value) {
return Object.assign({}, defaults[type], { value });
}
return Object.assign({}, defaults[type]);
}

View File

@ -3,12 +3,8 @@ import Hikes from './Hikes';
export default {
path: '/',
getChildRoutes(locationState, cb) {
setTimeout(() => {
cb(null, [
childRoutes: [
Jobs,
Hikes
]);
}, 0);
}
]
};

View File

@ -82,6 +82,10 @@
},
"descriptionPt": {
"type": "array"
},
"solutions": {
"type": "array",
"default": []
}
},
"validations": [],

View File

@ -1,6 +1,7 @@
{
"name": "job",
"base": "PersistedModel",
"strict": true,
"idInjection": true,
"trackChanges": false,
"properties": {
@ -29,6 +30,9 @@
"state": {
"type": "string"
},
"url": {
"type": "string"
},
"country": {
"type": "string"
},
@ -38,7 +42,7 @@
"description": {
"type": "string"
},
"isApproverd": {
"isApproved": {
"type": "boolean"
},
"isHighlighted": {

55
common/models/pledge.json Normal file
View File

@ -0,0 +1,55 @@
{
"name": "pledge",
"base": "PersistedModel",
"idInjection": true,
"trackChanges": false,
"properties": {
"nonprofit": {
"type": "string",
"index": true
},
"amount": {
"type": "number"
},
"dateStarted": {
"type": "date",
"defaultFn": "now"
},
"dateEnded": {
"type": "date"
},
"formerUserId": {
"type": "string"
},
"isOrphaned": {
"type": "boolean"
},
"isCompleted": {
"type": "boolean",
"default": "false"
}
},
"validations": [],
"relations": {
"user": {
"type": "hasMany",
"model": "user",
"foreignKey": "userId"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"accessType": "READ",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}

View File

@ -34,10 +34,6 @@
"description": {
"type": "string"
},
"originalStoryAuthorEmail": {
"type": "string",
"default": ""
},
"rank": {
"type": "number",
"default": 0

View File

@ -322,7 +322,7 @@ module.exports = function(User) {
})
// no results means this is the first brownie point given by giver
// so return -1 to indicate receiver should receive point
.firstOrDefault(null, -1)
.first({ defaultValue: -1 })
.flatMap((browniePointsFromGiver) => {
if (browniePointsFromGiver === -1) {

View File

@ -88,39 +88,6 @@
"google": {
"type": "string"
},
"completedBonfires": {
"type": [
{
"id": "string",
"name": "string",
"completedWith": "string",
"completedDate": "string",
"solution": "string"
}
],
"default": []
},
"uncompletedCoursewares": {
"type": "array",
"default": []
},
"completedCoursewares": {
"type": [
{
"completedDate": {
"type": "string",
"defaultFn": "now"
},
"id": "string",
"name": "string",
"completedWith": "string",
"solution": "string",
"githubLink": "string",
"verified": "boolean"
}
],
"default": []
},
"currentStreak": {
"type": "number",
"default": 0
@ -133,13 +100,39 @@
"type": "boolean",
"default": true
},
"isLocked": {
"type": "boolean",
"default": false,
"description": "Campers profile does not show challenges/certificates to the public"
},
"currentChallenge": {
"type": {}
},
"isUniqMigrated": {
"type": "boolean",
"default": false,
"description": "Campers completedChallenges array is free of duplicates"
},
"isHonest": {
"type": "boolean",
"default": false,
"description": "Camper has signed academic honesty policy"
},
"isFrontEndCert": {
"type": "boolean",
"defaut": false,
"description": "Camper is front end certified"
},
"isFullStackCert": {
"type": "boolean",
"default": false,
"description": "Campers is full stack certified"
},
"completedChallenges": {
"type": [
{
"completedDate": "number",
"lastUpdated": "number",
"id": "string",
"name": "string",
"completedWith": "string",
@ -157,6 +150,9 @@
"rand": {
"type": "number",
"index": true
},
"tshirtVote": {
"type": "number"
}
},
"validations": [],
@ -170,6 +166,11 @@
"type": "hasMany",
"model": "userIdentity",
"foreignKey": ""
},
"pledge": {
"type": "hasOne",
"model": "pledge",
"foreignKey": ""
}
},
"acls": [

View File

@ -1,3 +1,6 @@
// enable debug for gulp
process.env.DEBUG = process.env.DEBUG || 'freecc:*';
require('babel-core/register');
var Rx = require('rx'),
gulp = require('gulp'),
@ -6,6 +9,7 @@ var Rx = require('rx'),
// utils
plumber = require('gulp-plumber'),
notify = require('gulp-notify'),
gutil = require('gulp-util'),
reduce = require('gulp-reduce-file'),
sortKeys = require('sort-keys'),
debug = require('debug')('freecc:gulp'),
@ -25,6 +29,7 @@ var Rx = require('rx'),
// rev
rev = require('gulp-rev'),
revReplace = require('gulp-rev-replace'),
revDel = require('rev-del'),
// lint
jsonlint = require('gulp-jsonlint'),
@ -33,6 +38,7 @@ var Rx = require('rx'),
Rx.config.longStackSupport = true;
var __DEV__ = process.env.NODE_ENV !== 'production';
var reloadDelay = 1000;
var reload = sync.reload;
var paths = {
@ -43,6 +49,8 @@ var paths = {
'!public/js/bundle*',
'node_modules/',
'client/',
'seed',
'server/manifests/*.json',
'server/rev-manifest.json'
],
@ -67,11 +75,11 @@ var paths = {
],
dependents: [
'client/commonFramework.js',
'client/sandbox.js'
'client/commonFramework.js'
],
less: './client/less/main.less',
lessFiles: './client/less/*.less',
manifest: 'server/manifests/',
@ -107,11 +115,22 @@ function errorHandler() {
this.emit('end');
}
function delRev(dest, manifestName) {
// in production do not delete old revisions
if (!__DEV__) {
return gutil.noop();
}
return revDel({
oldManifest: path.join(paths.manifest, manifestName),
dest: dest
});
}
gulp.task('serve', function(cb) {
var called = false;
nodemon({
script: paths.server,
ext: '.js .json',
ext: '.jsx .js .json',
ignore: paths.serverIgnore,
exec: path.join(__dirname, 'node_modules/.bin/babel-node'),
env: {
@ -143,7 +162,7 @@ var syncDepenedents = [
'js',
'less',
'dependents',
'pack-client',
'pack-watch',
'build-manifest'
];
@ -173,6 +192,9 @@ gulp.task('lint-json', function() {
gulp.task('test-challenges', ['lint-json']);
gulp.task('pack-client', function() {
var manifestName = 'react-manifest.json';
var dest = webpackConfig.output.path;
return gulp.src(webpackConfig.entry)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
@ -180,30 +202,73 @@ gulp.task('pack-client', function() {
webpackConfig,
webpackOptions
)))
.pipe(gulp.dest(webpackConfig.output.path))
.pipe(gulp.dest(dest))
.pipe(rev())
// copy files to public
.pipe(gulp.dest(webpackConfig.output.path))
// create and merge manifest
.pipe(rev.manifest('react-manifest.json'))
.pipe(gulp.dest(dest))
// create manifest
.pipe(rev.manifest(manifestName))
// delete old rev
.pipe(delRev(
dest,
manifestName
))
.pipe(gulp.dest(paths.manifest));
});
gulp.task('pack-watch', function() {
return gulp.src(webpackConfig.entry)
var defaultStatsOptions = {
colors: gutil.colors.supportsColor,
hash: false,
timings: false,
chunks: false,
chunkModules: false,
modules: false,
children: true,
version: true,
cached: false,
cachedAssets: false,
reasons: false,
source: false,
errorDetails: false
};
gulp.task('pack-watch', function(cb) {
var called = false;
gulp.src(webpackConfig.entry)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(webpack(Object.assign(
{},
webpackConfig,
webpackOptions,
{ watch: true }
)))
.pipe(gulp.dest(webpackConfig.output.path))
), null, function(notUsed, stats) {
if (stats) {
gutil.log(stats.toString(defaultStatsOptions));
}
if (!called) {
debug('webpack watch completed');
called = true;
cb();
}
}))
.pipe(gulp.dest(webpackConfig.output.path));
});
gulp.task('pack-watch-manifest', function() {
var manifestName = 'react-manifest.json';
var dest = webpackConfig.output.path;
return gulp.src(dest + '/bundle.js')
.pipe(rev())
// copy files to public
.pipe(gulp.dest(webpackConfig.output.path))
.pipe(gulp.dest(dest))
// create manifest
.pipe(rev.manifest('react-manifest.json'))
.pipe(rev.manifest(manifestName))
.pipe(delRev(
dest,
manifestName
))
.pipe(gulp.dest(paths.manifest));
});
@ -217,32 +282,45 @@ gulp.task('pack-node', function() {
gulp.task('pack', ['pack-client', 'pack-node']);
gulp.task('less', function() {
var manifestName = 'css-manifest.json';
var dest = paths.css;
return gulp.src(paths.less)
.pipe(plumber({ errorHandler: errorHandler }))
// copile
.pipe(less({
paths: [ path.join(__dirname, 'less', 'includes') ]
}))
.pipe(gulp.dest(paths.css))
.pipe(gulp.dest(dest))
// add revision
.pipe(rev())
// copy files to public
.pipe(gulp.dest(paths.css))
.pipe(gulp.dest(dest))
// create and merge manifest
.pipe(rev.manifest('css-manifest.json'))
.pipe(rev.manifest(manifestName))
.pipe(delRev(
dest,
manifestName
))
.pipe(gulp.dest(paths.manifest));
});
gulp.task('js', function() {
var manifestName = 'js-manifest.json';
var dest = paths.publicJs;
return gulp.src(paths.js)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(gulp.dest(paths.publicJs))
.pipe(gulp.dest(dest))
// create registry file
.pipe(rev())
// copy revisioned assets to dest
.pipe(gulp.dest(paths.publicJs))
.pipe(gulp.dest(dest))
// create manifest file
.pipe(rev.manifest('js-manifest.json'))
.pipe(rev.manifest(manifestName))
.pipe(delRev(
dest,
manifestName
))
// copy manifest file to dest
.pipe(gulp.dest(paths.manifest));
});
@ -250,6 +328,9 @@ gulp.task('js', function() {
// commonFramework depend on iFrameScripts
// sandbox depends on plugin
gulp.task('dependents', ['js'], function() {
var manifestName = 'dependents-manifest.json';
var dest = paths.publicJs;
var manifest = gulp.src(
path.join(__dirname, paths.manifest, 'js-manifest.json')
);
@ -257,9 +338,14 @@ gulp.task('dependents', ['js'], function() {
return gulp.src(paths.dependents)
.pipe(plumber({ errorHandler: errorHandler }))
.pipe(revReplace({ manifest: manifest }))
.pipe(gulp.dest(dest))
.pipe(rev())
.pipe(gulp.dest(paths.publicJs))
.pipe(rev.manifest('dependents-manifest.json'))
.pipe(gulp.dest(dest))
.pipe(rev.manifest(manifestName))
.pipe(delRev(
dest,
manifestName
))
.pipe(gulp.dest(paths.manifest));
});
@ -301,17 +387,27 @@ var watchDependents = [
'dependents',
'serve',
'sync',
'build-manifest'
'build-manifest',
'pack-watch',
'pack-watch-manifest'
];
gulp.task('watch', watchDependents, function() {
gulp.watch(paths.less, ['less']);
gulp.watch(paths.lessFiles, ['less']);
gulp.watch(paths.js, ['js']);
gulp.watch(paths.challenges, ['test-challenges']);
gulp.watch(paths.js, ['js', 'dependents']);
gulp.watch(paths.dependents, ['dependents']);
gulp.watch(paths.manifest + '/*.json', ['build-manifest-watch']);
gulp.watch(webpackConfig.output.path + '/bundle.js', ['pack-watch-manifest']);
});
gulp.task('default', ['less', 'serve', 'sync', 'watch', 'pack-watch']);
gulp.task('default', [
'less',
'serve',
'pack-watch',
'pack-watch-manifest',
'watch',
'sync'
]);

View File

@ -6,30 +6,22 @@
"url": "https://github.com/freecodecamp/freecodecamp.git"
},
"scripts": {
"first-time": "npm run create-rev && echo '\n\nseeding database\n\n' && node seed && node seed/nonprofits",
"create-rev": "test ! -e server/rev-manifest.json && echo '\n\ncreating manifest\n\n' && touch server/rev-manifest.json && echo '{}' >> server/rev-manifest.json",
"build": "gulp build",
"start": "babel-node server/server.js",
"prestart-production": "bower cache clean && bower install && gulp build",
"start-production": "node pm2Start",
"lint": "eslint --ext=.js,.jsx .",
"test": "mocha --compilers js:babel/register"
"test": "gulp test-challenges"
},
"license": "(BSD-3-Clause AND CC-BY-SA-4.0)",
"contributors": [
{
"name": "Quincy Larson",
"url": "https://github.com/QuincyLarson"
},
{
"name": "Nathan Leniz",
"url": "https://github.com/terakilobyte"
}
],
"dependencies": {
"accepts": "~1.2.5",
"async": "~0.9.0",
"babel": "5.6.14",
"babel-core": "5.6.15",
"babel-eslint": "^4.0.5",
"babel": "5.8.23",
"babel-core": "5.8.23",
"babel-eslint": "4.1.1",
"babel-loader": "5.2.2",
"bcrypt-nodejs": "~0.0.3",
"body-parser": "^1.13.2",
@ -46,6 +38,7 @@
"dedent": "^0.4.0",
"dotenv": "~0.4.0",
"errorhandler": "~1.3.0",
"es6-map": "^0.1.1",
"eslint": "^1.1.0",
"eslint-plugin-react": "^3.2.1",
"express": "~4.10.4",
@ -58,21 +51,29 @@
"forever": "~0.14.1",
"frameguard": "^0.2.2",
"github-api": "~0.7.0",
"gulp": "~3.8.8",
"gulp-eslint": "~0.9.0",
"gulp-inject": "~1.0.2",
"gulp-jsonlint": "^1.1.0",
"gulp-nodemon": "^2.0.3",
"gulp-notify": "^2.2.0",
"gulp-plumber": "^1.0.1",
"gulp-less": "^3.0.3",
"gulp-minify-css": "~0.5.1",
"gulp-reduce-file": "0.0.1",
"gulp-rev": "^6.0.1",
"gulp-rev-replace": "^0.4.2",
"gulp-util": "^3.0.6",
"gulp-webpack": "^1.5.0",
"helmet": "~0.9.0",
"helmet-csp": "^0.2.3",
"history": "^1.9.0",
"jade": "~1.8.0",
"json-loader": "^0.5.2",
"less": "~1.7.5",
"less-middleware": "~2.0.1",
"less": "~2.5.1",
"lodash": "^3.9.3",
"loopback": "https://github.com/FreeCodeCamp/loopback.git#fix/no-password",
"loopback-boot": "2.8.2",
"loopback": "^2.22.0",
"loopback-boot": "^2.13.0",
"loopback-component-passport": "https://github.com/FreeCodeCamp/loopback-component-passport.git#feature/flashfailure",
"loopback-connector-mongodb": "^1.10.0",
"lusca": "~1.0.2",
@ -95,40 +96,33 @@
"pmx": "^0.3.16",
"ramda": "~0.10.0",
"react": "^0.13.3",
"react-bootstrap": "^0.23.7",
"react-bootstrap": "~0.23.7",
"react-motion": "~0.1.0",
"react-router": "https://github.com/BerkeleyTrue/react-router#freecodecamp",
"react-router": "https://github.com/BerkeleyTrue/react-router.git#freecodecamp",
"react-vimeo": "^0.0.3",
"request": "~2.53.0",
"rx": "^2.5.3",
"rev-del": "^1.0.5",
"rx": "^4.0.0",
"sanitize-html": "~1.6.1",
"sort-keys": "^1.1.1",
"source-map-support": "^0.3.2",
"thundercats": "^2.1.0",
"thundercats-react": "^0.1.0",
"store": "https://github.com/berkeleytrue/store.js.git#feature/noop-server",
"thundercats": "^3.0.0",
"thundercats-react": "^0.3.0",
"twit": "~1.1.20",
"uglify-js": "~2.4.15",
"validator": "~3.22.1",
"validator": "^3.22.1",
"webpack": "^1.9.12",
"xss-filters": "^1.2.6",
"yui": "~3.18.1"
},
"devDependencies": {
"babel-eslint": "^3.1.7",
"blessed": "~0.0.37",
"bower-main-files": "~0.0.4",
"browser-sync": "~1.8.1",
"browserify": "^10.2.4",
"chai": "~1.10.0",
"envify": "^3.4.0",
"eslint": "^0.21.2",
"eslint-plugin-react": "^2.3.0",
"gulp": "~3.8.8",
"gulp-eslint": "~0.9.0",
"gulp-inject": "~1.0.2",
"gulp-jsonlint": "^1.1.0",
"gulp-nodemon": "^2.0.3",
"gulp-notify": "^2.2.0",
"gulp-plumber": "^1.0.1",
"istanbul": "^0.3.15",
"loopback-explorer": "^1.7.2",
"loopback-testing": "^1.1.0",

9
public/css/lato.css Normal file
View File

@ -0,0 +1,9 @@
@font-face {
font-family: "Lato";
src: url(/fonts/Lato-Regular.ttf) format("truetype");
}
@font-face {
font-family: "Lato Light";
src: url(/fonts/Lato-Light.ttf) format("truetype");
}

9
public/css/ubuntu.css Normal file
View File

@ -0,0 +1,9 @@
@font-face {
font-family: "Ubuntu";
src: url(/fonts/Ubuntu-Regular.ttf) format("truetype");
}
@font-face {
font-family: "Ubuntu Mono";
src: url(/fonts/UbuntuMono-Regular.ttf) format("truetype");
}

0
public/fonts/Lato-Light.ttf Executable file → Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

0
public/fonts/ionicons.eot Executable file → Normal file
View File

0
public/fonts/ionicons.svg Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 326 KiB

After

Width:  |  Height:  |  Size: 326 KiB

0
public/fonts/ionicons.ttf Executable file → Normal file
View File

0
public/fonts/ionicons.woff Executable file → Normal file
View File

BIN
public/fonts/saxmono.ttf Executable file

Binary file not shown.

View File

@ -1,19 +1,20 @@
// MDN Links
/**
* MDN Links
*
* These links are for Bonfires. Each key/value pair is used to render a Bonfire with appropriate links.
* The text of the key is what the link text will be, e.g. <a href="https://developer ...">Global Array Object</a>
* General convention is to use the page title of the MDN reference page.
*
**/
/* These links are for Bonfires. Each key/value pair is used to render a Bonfire with appropriate links.
The text of the key is what the link text will be, e.g. <a href="https://developer ...">Global Array Object</a>
General convention is to use the page title of the MDN reference page.
*/
var links =
{
var links = {
// ========= NON MDN REFS
"Currying": "https://leanpub.com/javascript-allonge/read#pabc",
"Smallest Common Multiple": "https://www.mathsisfun.com/least-common-multiple.html",
"Permutations": "https://www.mathsisfun.com/combinatorics/combinations-permutations.html",
"HTML Entities": "http://dev.w3.org/html5/html-author/charref",
"Symmetric Difference": "https://www.youtube.com/watch?v=PxffSUQRkG4",
"Roman Numerals": "http://www.mathsisfun.com/roman-numerals.html",
// ========= GLOBAL OBJECTS
"Global Array Object": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",
@ -56,6 +57,7 @@ var links =
"String.toLowerCase()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase",
"String.toString()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toString",
"String.toUpperCase()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase",
// ======== ARRAY METHODS
"Array.concat()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat",
"Array.every()": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every",

View File

@ -1,41 +1,48 @@
{
"name": "Advanced Algorithm Scripting",
"order": 0.013,
"order": 15,
"time": "50h",
"challenges": [
{
"id": "aff0395860f5d3034dc0bfc9",
"title": "Validate US Telephone Numbers",
"difficulty": "4.01",
"description": [
"Return true if the passed string is a valid US phone number",
"The user may fill out the form field any way they choose as long as it is a valid US number. The following are all valid formats for US numbers:",
"555-555-5555, (555)555-5555, (555) 555-5555, 555 555 5555, 5555555555, 1 555 555 5555",
"For this challenge you will be presented with a string such as \"800-692-7753\" or \"8oo-six427676;laskdjf\". 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 \"1\". Return true if the string is a valid US phone number; otherwise false.",
"<code>555-555-5555</code>",
"<code>(555)555-5555</code>",
"<code>(555) 555-5555</code>",
"<code>555 555 5555</code>",
"<code>5555555555</code>",
"<code>1 555 555 5555</code>",
"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 true if the string is a valid US phone number; otherwise false.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"tests": [
"expect(telephoneCheck(\"555-555-5555\")).to.be.a(\"boolean\");",
"assert.deepEqual(telephoneCheck(\"1 555-555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"1 (555) 555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"5555555555\"), true);",
"assert.deepEqual(telephoneCheck(\"555-555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"(555)555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"1(555)555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"1 555 555 5555\"), true);",
"assert.deepEqual(telephoneCheck(\"555-555-5555\"), true);",
"assert.deepEqual(telephoneCheck(\"1 456 789 4444\"), true);",
"assert.deepEqual(telephoneCheck(\"123**&!!asdf#\"), false);",
"assert.deepEqual(telephoneCheck(\"55555555\"), false);",
"assert.deepEqual(telephoneCheck(\"(6505552368)\"), false);",
"assert.deepEqual(telephoneCheck(\"2 (757) 622-7382\"), false);",
"assert.deepEqual(telephoneCheck(\"0 (757) 622-7382\"), false);",
"assert.deepEqual(telephoneCheck(\"-1 (757) 622-7382\"), false);",
"assert.deepEqual(telephoneCheck(\"2 757 622-7382\"), false);",
"assert.deepEqual(telephoneCheck(\"10 (757) 622-7382\"), false);",
"assert.deepEqual(telephoneCheck(\"27576227382\"), false);",
"assert.deepEqual(telephoneCheck(\"(275)76227382\"), false);",
"assert.deepEqual(telephoneCheck(\"2(757)6227382\"), false);",
"assert.deepEqual(telephoneCheck(\"2(757)622-7382\"), false);"
"assert.isBoolean(telephoneCheck(\"555-555-5555\"), 'message: should return a boolean.');",
"assert(telephoneCheck(\"1 555-555-5555\") === true, 'message: <code>telephoneCheck(\"1 555-555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1 (555) 555-5555\") === true, 'message: <code>telephoneCheck(\"1 (555) 555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"5555555555\") === true, 'message: <code>telephoneCheck(\"5555555555\")</code> should return true.');",
"assert(telephoneCheck(\"555-555-5555\") === true, 'message: <code>telephoneCheck(\"555-555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"(555)555-5555\") === true, 'message: <code>telephoneCheck(\"(555)555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1(555)555-5555\") === true, 'message: <code>telephoneCheck(\"1(555)555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1 555 555 5555\") === true, 'message: <code>telephoneCheck(\"1 555 555 5555\")</code> should return true.');",
"assert(telephoneCheck(\"555-555-5555\") === true, 'message: <code>telephoneCheck(\"555-555-5555\")</code> should return true.');",
"assert(telephoneCheck(\"1 456 789 4444\") === true, 'message: <code>telephoneCheck(\"1 456 789 4444\")</code> should return true.');",
"assert(telephoneCheck(\"123**&!!asdf#\") === false, 'message: <code>telephoneCheck(\"123**&!!asdf#\")</code> should return false.');",
"assert(telephoneCheck(\"55555555\") === false, 'message: <code>telephoneCheck(\"55555555\")</code> should return false.');",
"assert(telephoneCheck(\"(6505552368)\") === false, 'message: <code>telephoneCheck(\"(6505552368)\")</code> should return false');",
"assert(telephoneCheck(\"2 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"2 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"0 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"0 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"-1 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"-1 (757) 622-7382\")</code> should return false');",
"assert(telephoneCheck(\"2 757 622-7382\") === false, 'message: <code>telephoneCheck(\"2 757 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"10 (757) 622-7382\") === false, 'message: <code>telephoneCheck(\"10 (757) 622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"27576227382\") === false, 'message: <code>telephoneCheck(\"27576227382\")</code> should return false.');",
"assert(telephoneCheck(\"(275)76227382\") === false, 'message: <code>telephoneCheck(\"(275)76227382\")</code> should return false.');",
"assert(telephoneCheck(\"2(757)6227382\") === false, 'message: <code>telephoneCheck(\"2(757)6227382\")</code> should return false.');",
"assert(telephoneCheck(\"2(757)622-7382\") === false, 'message: <code>telephoneCheck(\"2(757)622-7382\")</code> should return false.');",
"assert(telephoneCheck(\"555)-555-5555\") === false, 'message: <code>telephoneCheck(\"555)555-5555\")</code> should return false.');",
"assert(telephoneCheck(\"(555-555-5555\") === false, 'message: <code>telephoneCheck(\"(555-555-5555\")</code> should return false.');"
],
"challengeSeed": [
"function telephoneCheck(str) {",
@ -50,6 +57,9 @@
"MDNlinks": [
"RegExp"
],
"solutions": [
"var re = /^(?:(?:\\+?1\\s*(?:[.-]\\s*)?)?(?:\\(\\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\\s*\\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\\s*(?:[.-]\\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\\s*(?:[.-]\\s*)?([0-9]{4})$/;\n\nfunction telephoneCheck(str) {\n return !!str.match(re);\n}\n\ntelephoneCheck(\"555-555-5555\");"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -66,7 +76,6 @@
{
"id": "a3f503de51cf954ede28891d",
"title": "Symmetric Difference",
"difficulty": "4.02",
"description": [
"Create a function that takes two or more arrays and returns an array of the symmetric difference of the provided arrays.",
"The mathematical term symmetric difference refers to the elements in two sets that are in either the first or second set, but not in both.",
@ -74,21 +83,23 @@
],
"challengeSeed": [
"function sym(args) {",
" return arguments;",
" return args;",
"}",
"",
"sym([1, 2, 3], [5, 2, 1, 4]);"
],
"tests": [
"assert.deepEqual(sym([1, 2, 3], [5, 2, 1, 4]), [3, 5, 4], 'should return an array of unique values');",
"assert.deepEqual(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'should return the symmetric difference of the given arrays');",
"assert.deepEqual(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'should return an array of unique values');",
"assert.deepEqual(sym([1, 1]), [1], 'should return an array of unique values');"
"assert.sameMembers(sym([1, 2, 3], [5, 2, 1, 4]), [3, 5, 4], 'message: <code>sym([1, 2, 3], [5, 2, 1, 4])</code> should return <code>[3, 5, 4]</code>.');",
"assert.sameMembers(sym([1, 2, 5], [2, 3, 5], [3, 4, 5]), [1, 4, 5], 'message: <code>sym([1, 2, 5], [2, 3, 5], [3, 4, 5])</code> should return <code>[1, 4, 5]</code>');",
"assert.sameMembers(sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5]), [1, 4, 5], 'message: <code>sym([1, 1, 2, 5], [2, 2, 3, 5], [3, 4, 5, 5])</code> should return <code>[1, 4, 5]</code>.');"
],
"MDNlinks": [
"Array.reduce()",
"Symmetric Difference"
],
"solutions": [
"function sym(args) {\n var index = -1;\n var length = arguments.length;\n var result;\n while (++index < length) {\n var array = arguments[index];\n result = result ? diff(result, array).concat(diff(array, result)) : array;\n }\n return result ? uniq(result) : [];\n}\n\nfunction uniq(arr) {\n var h = Object.create(null);\n var u = [];\n arr.forEach(function(v) {\n if (v in h) return;\n h[v] = true;\n u.push(v);\n });\n return u;\n}\n\nfunction diff(a, b) {\n var h = Object.create(null);\n b.forEach(function(v) {\n h[v] = true; \n });\n return a.filter(function(v) { return !(v in h);});\n}\nsym([1, 2, 3], [5, 2, 1, 4]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -105,7 +116,6 @@
{
"id": "aa2e6f85cab2ab736c9a9b24",
"title": "Exact Change",
"difficulty": "4.03",
"description": [
"Design a cash register drawer function that accepts purchase price as the first argument, payment as the second argument, and cash-in-drawer (cid) as the third argument.",
"cid is a 2d array listing available currency.",
@ -121,30 +131,34 @@
"}",
"",
"// Example cash-in-drawer array:",
"// [['PENNY', 1.01],",
"// ['NICKEL', 2.05],",
"// ['DIME', 3.10],",
"// ['QUARTER', 4.25],",
"// ['ONE', 90.00],",
"// ['FIVE', 55.00],",
"// ['TEN', 20.00],",
"// ['TWENTY', 60.00],",
"// ['ONE HUNDRED', 100.00]]",
"// [[\"PENNY\", 1.01],",
"// [\"NICKEL\", 2.05],",
"// [\"DIME\", 3.10],",
"// [\"QUARTER\", 4.25],",
"// [\"ONE\", 90.00],",
"// [\"FIVE\", 55.00],",
"// [\"TEN\", 20.00],",
"// [\"TWENTY\", 60.00],",
"// [\"ONE HUNDRED\", 100.00]]",
"",
"drawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);"
"drawer(19.50, 20.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]]);"
],
"tests": [
"expect(drawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]])).to.be.a('array');",
"expect(drawer(19.50, 20.00, [['PENNY', 0.01], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0]])).to.be.a('string');",
"expect(drawer(19.50, 20.00, [['PENNY', 0.50], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0]])).to.be.a('string');",
"assert.deepEqual(drawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]), [['QUARTER', 0.50]], 'return correct change');",
"assert.deepEqual(drawer(3.26, 100.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]), [['TWENTY', 60.00], ['TEN', 20.00], ['FIVE', 15], ['ONE', 1], ['QUARTER', 0.50], ['DIME', 0.20], ['PENNY', 0.04] ], 'return correct change with multiple coins and bills');",
"assert.deepEqual(drawer(19.50, 20.00, [['PENNY', 0.01], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0]]), 'Insufficient Funds', 'insufficient funds');",
"assert.deepEqual(drawer(19.50, 20.00, [['PENNY', 0.50], ['NICKEL', 0], ['DIME', 0], ['QUARTER', 0], ['ONE', 0], ['FIVE', 0], ['TEN', 0], ['TWENTY', 0], ['ONE HUNDRED', 0]]), \"Closed\", 'cash-in-drawer equals change');"
"assert.isArray(drawer(19.50, 20.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]]), 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]])</code> should return an array.');",
"assert.isString(drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return a string.');",
"assert.isString(drawer(19.50, 20.00, [[\"PENNY\", 0.50], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 0.50], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return a string.');",
"assert.deepEqual(drawer(19.50, 20.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]]), [[\"QUARTER\", 0.50]], 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]])</code> should return <code>[[\"QUARTER\", 0.50]]</code>.');",
"assert.deepEqual(drawer(3.26, 100.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]]), [[\"TWENTY\", 60.00], [\"TEN\", 20.00], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.50], [\"DIME\", 0.20], [\"PENNY\", 0.04]], 'message: <code>drawer(3.26, 100.00, [[\"PENNY\", 1.01], [\"NICKEL\", 2.05], [\"DIME\", 3.10], [\"QUARTER\", 4.25], [\"ONE\", 90.00], [\"FIVE\", 55.00], [\"TEN\", 20.00], [\"TWENTY\", 60.00], [\"ONE HUNDRED\", 100.00]])</code> should return <code>[[\"TWENTY\", 60.00], [\"TEN\", 20.00], [\"FIVE\", 15], [\"ONE\", 1], [\"QUARTER\", 0.50], [\"DIME\", 0.20], [\"PENNY\", 0.04]]</code>.');",
"assert.deepEqual(drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Insufficient Funds\".');",
"assert.deepEqual(drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1.00], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Insufficient Funds\", 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 0.01], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 1.00], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Insufficient Funds\".');",
"assert.deepEqual(drawer(19.50, 20.00, [[\"PENNY\", 0.50], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]]), \"Closed\", 'message: <code>drawer(19.50, 20.00, [[\"PENNY\", 0.50], [\"NICKEL\", 0], [\"DIME\", 0], [\"QUARTER\", 0], [\"ONE\", 0], [\"FIVE\", 0], [\"TEN\", 0], [\"TWENTY\", 0], [\"ONE HUNDRED\", 0]])</code> should return \"Closed\".');"
],
"MDNlinks": [
"Global Object"
],
"solutions": [
"var VALUES = [1, 5, 10, 25, 100, 500, 1000, 2000, 10000];\n\nfunction drawer(price, cash, cid) {\n cash = ~~(cash * 100);\n price = ~~(price * 100);\n var diff = cash-price;\n cid.forEach(function(c) {\n c[1] = ~~(c[1] * 100);\n });\n var totalCid = cid.reduce(function(a, c) {\n return a + c[1];\n }, 0);\n if (diff > totalCid) {\n return \"Insufficient Funds\";\n }\n if (diff === totalCid) {\n return \"Closed\";\n }\n \n var change = []; \n var index = cid.length;\n while (diff > 0 && --index > -1) {\n var t = 0;\n var value = VALUES[index];\n while (diff >= value && cid[index][1] > 0) {\n t += value;\n cid[index][1] -= value;\n diff -= value;\n }\n if (t) {\n change.push([cid[index][0], t/100]);\n }\n console.log(JSON.stringify(change));\n }\n // Here is your change, ma'am.\n return change;\n}\n\n// Example cash-in-drawer array:\n// [['PENNY', 1.01],\n// ['NICKEL', 2.05],\n// ['DIME', 3.10],\n// ['QUARTER', 4.25],\n// ['ONE', 90.00],\n// ['FIVE', 55.00],\n// ['TEN', 20.00],\n// ['TWENTY', 60.00],\n// ['ONE HUNDRED', 100.00]]\n\ndrawer(19.50, 20.00, [['PENNY', 1.01], ['NICKEL', 2.05], ['DIME', 3.10], ['QUARTER', 4.25], ['ONE', 90.00], ['FIVE', 55.00], ['TEN', 20.00], ['TWENTY', 60.00], ['ONE HUNDRED', 100.00]]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -161,7 +175,6 @@
{
"id": "a56138aff60341a09ed6c480",
"title": "Inventory Update",
"difficulty": "4.04",
"description": [
"Compare and update inventory stored in a 2d array against a second 2d array of a fresh delivery. Update current inventory item quantity, and if an item cannot be found, add the new item and quantity into the inventory array in alphabetical order.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -174,32 +187,35 @@
"",
"// Example inventory lists",
"var curInv = [",
" [21, 'Bowling Ball'],",
" [2, 'Dirty Sock'],",
" [1, 'Hair Pin'],",
" [5, 'Microphone']",
" [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']",
" [2, \"Hair Pin\"],",
" [3, \"Half-Eaten Apple\"],",
" [67, \"Bowling Ball\"],",
" [7, \"Toothpaste\"]",
"];",
"",
"inventory(curInv, newInv);"
],
"tests": [
"expect(inventory([[21, 'Bowling Ball'], [2, 'Dirty Sock'], [1, 'Hair Pin'], [5, 'Microphone']], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']])).to.be.a('array');",
"assert.equal(inventory([[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);",
"assert.deepEqual(inventory([[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']]);",
"assert.deepEqual(inventory([[21, 'Bowling Ball'], [2, 'Dirty Sock'], [1, 'Hair Pin'], [5, 'Microphone']], []), [[21, 'Bowling Ball'], [2, 'Dirty Sock'], [1, 'Hair Pin'], [5, 'Microphone']]);",
"assert.deepEqual(inventory([], [[2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [67, 'Bowling Ball'], [7, 'Toothpaste']]), [[67, 'Bowling Ball'], [2, 'Hair Pin'], [3, 'Half-Eaten Apple'], [7, 'Toothpaste']]);",
"assert.deepEqual(inventory([[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']]);"
"assert.isArray(inventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), 'message: <code>inventory()</code> should return an array.');",
"assert.equal(inventory([[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, 'message: <code>inventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]).length</code> should return an array with a length of 6.');",
"assert.deepEqual(inventory([[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\"]], 'message: <code>inventory([[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>.');",
"assert.deepEqual(inventory([[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], []), [[21, \"Bowling Ball\"], [2, \"Dirty Sock\"], [1, \"Hair Pin\"], [5, \"Microphone\"]], 'message: <code>inventory([[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>.');",
"assert.deepEqual(inventory([], [[2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [67, \"Bowling Ball\"], [7, \"Toothpaste\"]]), [[67, \"Bowling Ball\"], [2, \"Hair Pin\"], [3, \"Half-Eaten Apple\"], [7, \"Toothpaste\"]], 'message: <code>inventory([], [[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>.');",
"assert.deepEqual(inventory([[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\"]], 'message: <code>inventory([[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"
],
"solutions": [
"function inventory(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\ninventory(curInv, newInv);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -216,7 +232,6 @@
{
"id": "a7bf700cd123b9a54eef01d5",
"title": "No repeats please",
"difficulty": "4.05",
"description": [
"Return the number of total permutations of the provided string that don't have repeated consecutive letters.",
"For example, 'aab' should return 2 because it has 6 total permutations, but only 2 of them don't have the same letter (in this case 'a') repeating.",
@ -230,18 +245,21 @@
"permAlone('aab');"
],
"tests": [
"expect(permAlone('aab')).to.be.a('number');",
"expect(permAlone('aab')).to.equal(2);",
"expect(permAlone('aaa')).to.equal(0);",
"expect(permAlone('aabb')).to.equal(8);",
"expect(permAlone('abcdefa')).to.equal(3600);",
"expect(permAlone('abfdefa')).to.equal(2640);",
"expect(permAlone('zzzzzzzz')).to.equal(0);"
"assert.isNumber(permAlone('aab'), 'message: <code>permAlone()</code> should return a number.');",
"assert.strictEqual(permAlone('aab'), 2, 'message: <code>permAlone(aab)</code> should return 2.');",
"assert.strictEqual(permAlone('aaa'), 0, 'message: <code>permAlone(aaa)</code> should return 0.');",
"assert.strictEqual(permAlone('aabb'), 8, 'message: <code>permAlone(aabb)</code> should return 8.');",
"assert.strictEqual(permAlone('abcdefa'), 3600, 'message: <code>permAlone(abcdefa)</code> should return 3600.');",
"assert.strictEqual(permAlone('abfdefa'), 2640, 'message: <code>permAlone(abfdefa)</code> should return 2640.');",
"assert.strictEqual(permAlone('zzzzzzzz'), 0, 'message: <code>permAlone(zzzzzzzz)</code> should return 0.');"
],
"MDNlinks": [
"Permutations",
"RegExp"
],
"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"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -259,7 +277,6 @@
"id": "a19f0fbe1872186acd434d5a",
"title": "Friendly Date Ranges",
"dashedName": "bonfire-friendly-date-ranges",
"difficulty": "4.06",
"description": [
"Implement a way of converting two dates into a more friendly date range that could be presented to a user.",
"It must not show any redundant information in the date range.",
@ -276,18 +293,21 @@
"friendly(['2015-07-01', '2015-07-04']);"
],
"tests": [
"assert.deepEqual(friendly(['2015-07-01', '2015-07-04']), ['July 1st','4th'], 'ending month should be omitted since it is already mentioned');",
"assert.deepEqual(friendly(['2015-12-01', '2016-02-03']), ['December 1st','February 3rd'], 'two months apart can be inferred if it is the next year');",
"assert.deepEqual(friendly(['2015-12-01', '2017-02-03']), ['December 1st, 2015','February 3rd, 2017']);",
"assert.deepEqual(friendly(['2016-03-01', '2016-05-05']), ['March 1st','May 5th'], 'one month apart can be inferred it is the same year');",
"assert.deepEqual(friendly(['2017-01-01', '2017-01-01']), ['January 1st, 2017'], 'since we do not duplicate only return once');",
"assert.deepEqual(friendly(['2022-09-05', '2023-09-04']), ['September 5th, 2022','September 4th, 2023']);"
"assert.deepEqual(friendly(['2015-07-01', '2015-07-04']), ['July 1st','4th'], 'message: <code>friendly([\"2015-07-01\", \"2015-07-04\"])</code> should return <code>[\"July 1st\",\"4th\"]</code>.');",
"assert.deepEqual(friendly(['2015-12-01', '2016-02-03']), ['December 1st','February 3rd'], 'message: <code>friendly([\"2015-12-01\", \"2016-02-03\"])</code> should return <code>[\"December 1st\",\"February 3rd\"]</code>.');",
"assert.deepEqual(friendly(['2015-12-01', '2017-02-03']), ['December 1st, 2015','February 3rd, 2017'], 'message: <code>friendly([\"2015-12-01\", \"2017-02-03\"])</code> should return <code>[\"December 1st, 2015\",\"February 3rd, 2017\"]</code>.');",
"assert.deepEqual(friendly(['2016-03-01', '2016-05-05']), ['March 1st','May 5th'], 'message: <code>friendly([\"2016-03-01\", \"2016-05-05\"])</code> should return <code>[\"March 1st\",\"May 5th\"]</code>');",
"assert.deepEqual(friendly(['2017-01-01', '2017-01-01']), ['January 1st, 2017'], 'message: <code>friendly([\"2017-01-01\", \"2017-01-01\"])</code> should return <code>[\"January 1st, 2017\"]</code>.');",
"assert.deepEqual(friendly(['2022-09-05', '2023-09-04']), ['September 5th, 2022','September 4th, 2023'], 'message: <code>friendly([\"2022-09-05\", \"2023-09-04\"])</code> should return <code>[\"September 5th, 2022\",\"September 4th, 2023\"]</code>.');"
],
"MDNlinks": [
"String.split()",
"String.substr()",
"parseInt()"
],
"solutions": [
"function friendly(str) {\n var dates = str.map(function(s) {return s.split('-').map(Number);});\n var start = dates[0];\n var end = dates[1];\n if (str[0] === str[1]) {\n return [readable(start)];\n }\n if (start[0] !== end[0]) {\n if (start[0] + 1 === end[0] && start[1] > end[1]) {\n start[0] = undefined;\n end[0] = undefined;\n }\n return dates.map(readable);\n }\n start[0] = undefined;\n end[0] = undefined;\n if (start[1] !== end[1]) {\n return dates.map(readable);\n }\n end[1] = undefined;\n return dates.map(readable);\n}\n\nfunction readable(arr) {\n var ordD = arr[2] + nth(arr[2]);\n if (!arr[1]) {\n return ordD;\n }\n return MONTH[arr[1]] + \" \" + ordD + (!arr[0] ? \"\" : \", \" + arr[0]);\n}\n\nvar MONTH = {1: \"January\",\n 2: \"February\",\n 3: \"March\",\n 4: \"April\",\n 5: \"May\",\n 6: \"June\",\n 7: \"July\",\n 8: \"August\",\n 9: \"September\",\n 10: \"October\",\n 11: \"November\",\n 12: \"December\"};\n\nfunction nth(d) {\n if(d>3 && d<21) return 'th';\n switch (d % 10) {\n case 1: return \"st\";\n case 2: return \"nd\";\n case 3: return \"rd\";\n default: return \"th\";\n }\n} \n\nfriendly(['2015-07-01', '2015-07-04']);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",

View File

@ -1,11 +1,11 @@
{
"name": "AngularJS",
"order": 0.014,
"order": 16,
"time": "5h",
"challenges": [
{
"id": "bd7154d8c441eddfaeb5bdef",
"title": "Get Started with Angular.js",
"difficulty": 0.34,
"challengeSeed": ["114684726"],
"description": [
"Code School has a short, free Angular.js course. This will give us a quick tour of Angular.js's mechanics and features.",
@ -29,7 +29,6 @@
{
"id": "bd7155d8c441eddfaeb5bdef",
"title": "Apply Angular.js Directives",
"difficulty": 0.35,
"challengeSeed": ["114684727"],
"description": [
"Directives serve as markers in your HTML. When Angular.js compiles your HTML, it will alter the behavior of DOM elements based on the directives you've used.",
@ -53,7 +52,6 @@
{
"id": "bd7156d8c441eddfaeb5bdef",
"title": "Power Forms with Angular.js",
"difficulty": 0.36,
"challengeSeed": ["114684729"],
"description": [
"One area where Angular.js really shines is its powerful web forms.",
@ -77,7 +75,6 @@
{
"id": "bd7157d8c441eddfaeb5bdef",
"title": "Customize Angular.js Directives",
"difficulty": 0.37,
"challengeSeed": ["114685062"],
"description": [
"Now we'll learn how to modify existing Angular.js directives, and even build directives of your own.",
@ -100,7 +97,6 @@
{
"id": "bd7158d8c441eddfaeb5bdef",
"title": "Create Angular.js Services",
"difficulty": 0.38,
"challengeSeed": ["114685060"],
"description": [
"Services are functions that you can use and reuse throughout your Angular.js app to get things done.",

View File

@ -1,6 +1,7 @@
{
"name": "Automated Testing and Debugging",
"order": 0.012,
"order": 14,
"time": "15m",
"challenges": [
{
"id":"cf1111c1c16feddfaeb6bdef",
@ -13,7 +14,7 @@
"<code>console.log('Hello world!')</code>"
],
"tests":[
"assert(editor.getValue().match(/console\\.log\\(/gi), 'You should use the console.log method to log \"Hello world!\" to your JavaScript console.');"
"assert(editor.getValue().match(/console\\.log\\(/gi), 'message: You should use the console.log method to log \"Hello world!\" to your JavaScript console.');"
],
"challengeSeed":[
"",
@ -28,19 +29,19 @@
"title":"Using typeof",
"difficulty":0,
"description":[
"<code>typeof</code> is a useful method that we can use to check the type of a variable.",
"One thing to be careful of is that an array has the type objects.",
"Try using each of these to see the types they have.",
"You can use <code>typeof</code> to check the <code>data structure</code>, or type, of a variable.",
"Note that in JavaScript, arrays are technically a type of object.",
"Try using <code>typeof</code> on each of the following to see which types they have.",
"<code>console.log(typeof(\"\"));</code>",
"<code>console.log(typeof(0));</code>",
"<code>console.log(typeof([]));</code>",
"<code>console.log(typeof({}));</code>"
],
"tests":[
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\"\"\\)\\);/gi), 'You should <code>console.log</code> the <code>typeof</code> a string.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(0\\)\\);/gi), 'You should <code>console.log</code> the <code>typeof</code> a number.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\\[\\]\\)\\);/gi), 'You should <code>console.log</code> the <code>typeof</code> an array.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\\{\\}\\)\\);/gi), 'You should <code>console.log</code> the <code>typeof</code> a object.');"
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\"\"\\)\\);/gi), 'message: You should <code>console.log</code> the <code>typeof</code> a string.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(0\\)\\);/gi), 'message: You should <code>console.log</code> the <code>typeof</code> a number.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\\[\\]\\)\\);/gi), 'message: You should <code>console.log</code> the <code>typeof</code> an array.');",
"assert(editor.getValue().match(/console\\.log\\(typeof\\(\\{\\}\\)\\);/gi), 'message: You should <code>console.log</code> the <code>typeof</code> a object.');"
],
"challengeSeed":[
"",

View File

@ -1,72 +1,109 @@
{
"name": "Full Stack JavaScript Projects",
"order": 0.019,
"order": 20,
"time": "300h",
"challenges": [
{
"id": "bd7158d8c443eddfaeb5bcef",
"title": "Get Set for Basejumps",
"difficulty": 2.00,
"challengeSeed": ["128451852"],
"challengeSeed": [],
"description": [
"<span class='text-info'>Objective:</span> Get the MEAN stack running on Cloud 9, push your code to GitHub, and deploy it to Heroku.",
"We'll build our Basejumps on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.",
"If you don't already have Cloud 9 account, create one now at <a href='http://c9.io' target='_blank'>http://c9.io</a>.",
"Now let's get your development environment ready for a new Angular-Fullstack application provided by Yeoman.",
"Open up <a href='http://c9.io' target='_blank'>http://c9.io</a> and sign in to your account.",
"Click on Create New Workspace at the top right of the c9.io page, then click on the \"Create a new workspace\" popup that appears below it the button after you click on it.",
"Give your workspace a name.",
"Choose Node.js in the selection area below the name field.",
"Click the Create button. Then click into your new workspace.",
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
"Never run this command on your local machine. But in your Cloud 9 terminal window, run: <code>rm -rf * && echo \"export NODE_PATH=$NODE_PATH:/home/ubuntu/.nvm/v0.10.35/lib/node_modules\" >> ~/.bashrc && source ~/.bashrc && npm install -g yo grunt grunt-cli generator-angular-fullstack && yo angular-fullstack</code>",
"Yeoman will prompt you to answer some questions. Answer them like this:",
"What would you like to write scripts with? <span class='text-success'>JavaScript</span>",
"What would you like to write markup with? <span class='text-success'>HTML</span>",
"What would you like to write stylesheets with? <span class='text-success'>CSS</span>",
"What Angular router would you like to use? <span class='text-success'>ngRoute</span>",
"Would you like to include Bootstrap? <span class='text-success'>Yes</span>",
"Would you like to include UI Bootstrap? <span class='text-success'>Yes</span>",
"Would you like to use MongoDB with Mongoose for data modeling? <span class='text-success'>Yes</span>",
"Would you scaffold out an authentication boilerplate? <span class='text-success'>Yes</span>",
"Would you like to include additional oAuth strategies? <span class='text-success'>Twitter</span>",
"Would you like to use socket.io? <span class='text-success'>No</span>",
"May bower anonymously report usage statistics to improve the tool over time? (Y/n) <span class='text-success'>Y</span>",
"You may get an error similar to <code> ERR! EEXIST, open /home/ubuntu/.npm</code>. This is caused when Cloud9 runs out of memory and kills an install. If you get this, simply re-run this process with the command <code>yo angular-fullstack</code>. You will then be asked a few questions regarding the re-install. Answer them as follows:",
"Existing .yo-rc configuration found, would you like to use it? (Y/n) <span class='text-success'>Y</span>",
"Overwrite client/favicon.ico? (Ynaxdh) <span class='text-success'>Y</span>",
"To finish the installation run the commands: <code>bower install && npm install</code>",
"To start MongoDB, run the following commands in your terminal: <code>mkdir data && echo 'mongod --bind_ip=$IP --dbpath=data --nojournal --rest \"$@\"' > mongod && chmod a+x mongod && ./mongod</code>",
"You will want to open up a new terminal to work from by clicking on the + icon and select New Terminal",
"Start the application by running the following command in your new terminal window: <code>grunt serve</code>",
"Wait for the following message to appear: <code>xdg-open: no method available for opening 'http://localhost:8080' </code>. Now you can open the internal Cloud9 browser. To launch the browser select Preview in the toolbar then select the dropdown option Preview Running Application.",
"Turn the folder in which your application is running into a Git repository by running the following commands: <code>git init && git add . && git commit -am 'initial commit'</code>.",
"Now we need to add your GitHub SSH key to c9.io. Click the \"Add-on Services\" button in the lower left of your C9 dashboard. Click \"activate\" next to the GitHub icon.",
"A pop up will appear. Allow access to your account.",
"While still on the dashboard, under “Account Settings”, click the link for \"Show your SSH key\". Copy the key to you clipboard.",
"Sign in to <a href='http://github.com' target='_blank'>http://github.com</a> and navigate to the GitHub SSH settings page. Click the \"Add SSH Key\". Give your key the title \"cloud 9\". Paste your SSH Key into the \"Key\" box, then click \"Add Key\".",
"Create a new GitHub repository by and clicking on the + button next to your username in the upper-right hand side of your screen, then selecting \"New Repository\".",
"Enter a project name, then click the \"Create Repository\" button.",
"Find the \"...or push an existing repository from the command line\" section and click the Copy to Clipboard button beside it.",
"Paste the commands from your clipboard into the Cloud9 terminal prompt. This will push your changes to your repository on Cloud 9 up to GitHub.",
"Check back on your GitHub profile to verify the changes were successfully pushed up to GitHub.",
"Now let's push your code to Heroku. If you don't already have a Heroku account, create one at <a href='http://heroku.com' target='_blank'>http://heroku.com</a>. You shouldn't be charged for anything, but you will need to add your credit card information to your Heroku before you will be able to use Heroku's free MongoLab add on.",
"Before you publish to Heroku, you should free up as much memory as possible on Cloud9. In each of the Cloud9 terminal prompt tabs where MongoDB and Grunt are running, press the <code>control + c</code> hotkey to shut down these processes.",
"Run the following command in a Cloud9 terminal prompt tab: <code>npm install grunt-contrib-imagemin --save-dev && npm install --save-dev && heroku login</code>. At this point, the terminal will prompt you to log in to Heroku from the command line.",
"Now run <code>yo angular-fullstack:heroku</code>. You can choose a name for your Heroku project, or Heroku will create a random one for you. You can choose whether you want to deploy to servers the US or the EU.",
"Set the config flag for your Heroku environment and add MongoLab for your MongoDB instance by running the following command: <code>cd ~/workspace/dist && heroku config:set NODE_ENV=production && heroku addons:create mongolab</code>.",
"As you build your app, you should frequently commit changes to your codebase. Make sure you're in the <code>~/workspace</code> directory by running <code>cd ~/workspace</code>. Then you can this code to stage the changes to your changes and commit them: <code>git commit -am \"your commit message\"</code>. Note that you should replace \"your commit message\" with a short summary of the changes you made to your code, such as \"added a records controller and corresponding routes\".",
"You can push these new commits to GitHub by running <code>git push origin master</code>, and to Heroku by running <code>grunt --force && grunt buildcontrol:heroku</code>.",
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"Now you're ready to move on to your first Basejump. Click the \"I've completed this challenge\" and move on."
[
"http://i.imgur.com/4IZjWZ3.gif",
"A gif showing how to create a c9.io account.",
"We recommend building our full stack Basejump challenges on c9.io, a powerful browser-based development environment. This save you hours of time that you would spend configuring your local computer to run Node.js and MongoDB - time you could instead spend coding. <br>Create a c9.io account by clicking the GitHub symbol in the upper right hand corner of the c9.io page. Click the big plus symbol to create a new workspace. Enter your email address when prompted.",
"http://c9.io"
],
"type": "waypoint",
"challengeType": 2,
"tests": []
[
"http://i.imgur.com/F7i5Hhi.gif",
"A gif showing how to fill out the new workspace form",
"Instead of starting from scratch, we recommend using Clementine.js, a full stack JavaScript \"boilerplate\" that already has some basic code written for you. Clementine.js has a detailed tutorial you can go through to build it yourself, but for now let's just clone its code. On c9.io, give your workspace a name, then leave \"Template\" as custom and create your workspace from this GitHub url: <code>https://github.com/johnstonbl01/clementinejs-fcc.git</code>",
""
],
[
"http://i.imgur.com/42m1vyr.gif",
"A gif showing you how to show hidden files.",
"Click the gear in the upper right corner of c9.io's file structure. Select \"show hidden files\".",
""
],
[
"http://i.imgur.com/qrE8xaK.gif",
"A gif showing you how to create a new file.",
"Right click and create a new file called <code>.env</code>.",
""
],
[
"http://i.imgur.com/jkQX9SQ.gif",
"A gif showing you how to prep your environmental variables in your .env file.",
"Open your .env file and paste this into it, then save it: <br><code>GITHUB_KEY=<br>GITHUB_SECRET=<br>MONGO_URI=mongodb://localhost:27017/clementinejs<br>PORT=8080<br>APP_URL=http://localhost:8080/</code>",
""
],
[
"http://i.imgur.com/f3DE7zB.gif",
"A gif showing you how to open c9.io's preview window.",
"Open up your application in a preview tab by clicking window > share > application > open.",
""
],
[
"http://i.imgur.com/Ip0qUdQ.gif",
"A gif showing you how to create a GitHub app using c9.io's preview URL.",
"Create a GitHub app for authentication and choose an \"Application name\". For the homepage URL, paste the URL from your preview tab. You'll also paste the URL from your preview tab into \"Authorization callback URL\", then add to it: <code>auth/github/callback</code>",
"https://github.com/settings/applications/new"
],
[
"http://i.imgur.com/qCUVRFb.gif",
"A gif showing you how to transfer GitHub's key and secret over to your .env file, as well as your c9.io URL.",
"GitHub will create an app and present you with a Client ID and a Client Secret. Set your .env file's GITHUB_KEY equal to the Client ID, and set your .env file's GITHUB_SECRET equal to the Client Secret. Copy the URL from the your preview tab and paste it into your .env file as your APP_URL.",
""
],
[
"http://i.imgur.com/2a20Vah.gif",
"A gif showing you how to start mongoDB in c9.io's terminal.",
"In your terminal, start MongoDB by entering <code>mongod --smallfiles</code>",
""
],
[
"http://i.imgur.com/dC55pWk.gif",
"A gif showing you how to open a new tab in c9.io's terminal.",
"Open a new terminal tab with the + button above your terminal, then run <code>npm install</code>",
""
],
[
"http://i.imgur.com/54OC2Ro.gif",
"A gif showing you how to navigate to your preview tab and sign in to your new Clementine.js app.",
"Run <code>node server.js</code> to start the server. Refresh your preview tab. You should see the Clementine.js logo. Click \"sign in\" and accept GitHub's prompt to authorize the application.",
""
],
[
"http://i.imgur.com/2IJfyvN.gif",
"A gif showing you how to click the button to trigger an AJAX action with Clementine.js and how to look at your user profile from the GitHub authentication data.",
"Click the \"click me\" button and you'll see that it increments the number clicks. Click the profile button and you'll see that it has your GitHub information.",
""
],
[
"http://i.imgur.com/bjO5pnq.gif",
"A gif showing you how to create a new GitHub repository and push your code up to it.",
"Create a new GitHub repository. Then copy its .git URL. <br>Return to c9.io's terminal and set your GitHub remote URL: <code>git remote set-url origin</code> followed by the URL you copied from GitHub. <br>Run <code>git push origin master</code>. <br>Now tab back to GitHub and refresh, and you'll see that your code is now on GitHub.",
"https://github.com/new"
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c443eddfaeb5bdef",
"title": "Build a Voting App",
"difficulty": 2.01,
"challengeSeed": ["133315786"],
"description": [
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://votingapp.herokuapp.com/' target='_blank'>http://votingapp.herokuapp.com/</a> and deploy it to Heroku.",
@ -79,14 +116,14 @@
"<span class='text-info'>User Story:</span> As an authenticated user, I can see the aggregate results of my polls.",
"<span class='text-info'>User Story:</span> As an authenticated user, I can delete polls that I decide I don't want anymore.",
"<span class='text-info'>User Story:</span> As an authenticated user, I can create a poll with any number of possible items.",
"<span class='text-info'>Bonus User Story:</span> As an unauthenticated user, I can see everyone's polls, but I can't vote on anything.",
"<span class='text-info'>Bonus User Story:</span> As an unauthenticated or authenticated user, I can see and vote on everyone's polls.",
"<span class='text-info'>Bonus User Story:</span> 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.)",
"<span class='text-info'>Bonus User Story:</span> As an authenticated user, if I don't like the options on a poll, I can create a new option.",
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"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. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "basejumps",
"type": "basejump",
"challengeType": 4,
"tests": [],
"nameCn": "",
@ -103,7 +140,6 @@
{
"id": "bd7158d8c443eddfaeb5bdff",
"title": "Build a Nightlife Coordination App",
"difficulty": 2.02,
"challengeSeed": ["133315781"],
"description": [
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://whatsgoinontonight.herokuapp.com/' target='_blank'>http://whatsgoinontonight.herokuapp.com/</a> and deploy it to Heroku.",
@ -118,9 +154,9 @@
"<span class='text-info'>Hint:</span> 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 need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"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. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "basejumps",
"type": "basejump",
"challengeType": 4,
"tests": [],
"nameCn": "",
@ -137,7 +173,6 @@
{
"id": "bd7158d8c443eddfaeb5bd0e",
"title": "Chart the Stock Market",
"difficulty": 2.03,
"challengeSeed": ["133315787"],
"description": [
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://stockstream.herokuapp.com/' target='_blank'>http://stockstream.herokuapp.com/</a> and deploy it to Heroku.",
@ -151,9 +186,9 @@
"<span class='text-info'>Bonus User Story:</span> As a user, I can see changes in real-time when any other user adds or removes a stock.",
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"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. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "basejumps",
"type": "basejump",
"challengeType": 4,
"tests": [],
"nameCn": "",
@ -170,7 +205,6 @@
{
"id": "bd7158d8c443eddfaeb5bd0f",
"title": "Manage a Book Trading Club",
"difficulty": 2.04,
"challengeSeed": ["133316032"],
"description": [
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://bookjump.herokuapp.com/' target='_blank'>http://bookjump.herokuapp.com/</a> and deploy it to Heroku.",
@ -184,9 +218,9 @@
"<span class='text-info'>Bonus User Story:</span> As an authenticated user, I can propose a trade and wait for the other user to accept the trade.",
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"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. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "basejumps",
"type": "basejump",
"challengeType": 4,
"tests": [],
"nameCn": "",
@ -203,7 +237,6 @@
{
"id": "bd7158d8c443eddfaeb5bdee",
"title": "Build a Pinterest Clone",
"difficulty": 2.05,
"challengeSeed": ["133315784"],
"description": [
"<span class='text-info'>Objective:</span> Build a full stack JavaScript app that successfully reverse-engineers this: <a href='http://stark-lowlands-3680.herokuapp.com/' target='_blank'>http://stark-lowlands-3680.herokuapp.com/</a> and deploy it to Heroku.",
@ -220,9 +253,9 @@
"<span class='text-info'>Hint:</span> <a href='http://masonry.desandro.com/' target='_blank'>Masonry.js</a> is a library that allows for Pinterest-style image grids.",
"If you need further guidance on using Yeoman Angular-Fullstack Generator, check out: <a href='https://github.com/clnhll/guidetobasejumps' target='_blank'>https://github.com/clnhll/guidetobasejumps</a>.",
"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. If you pair programmed with a friend, enter his or her Free Code Camp username as well so that you both get credit for completing it.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your Heroku project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "basejumps",
"type": "basejump",
"challengeType": 4,
"tests": [],
"nameCn": "",

View File

@ -1,20 +1,20 @@
{
"name": "Basic Algorithm Scripting",
"order": 0.006,
"order": 8,
"time": "50h",
"challenges": [
{
"id": "ad7123c8c441eddfaeb5bdef",
"title": "Meet Bonfire",
"difficulty": "0",
"description": [
"Your goal is to fix the failing test.",
"First, run all the tests by clicking \"Run code\" or by pressing Control + Enter.",
"First, run all the tests by clicking \"Run tests\" or by pressing Control + Enter.",
"The failing test is in red. Fix the code so that all tests pass. Then you can move on to the next Bonfire.",
"Make this function return true no matter what."
],
"tests": [
"expect(meetBonfire()).to.be.a(\"boolean\");",
"expect(meetBonfire()).to.be.true;"
"assert(typeof(meetBonfire()) === \"boolean\", 'message: <code>meetBonfire()</code> should return a boolean value.');",
"assert(meetBonfire() === true, 'message: <code>meetBonfire()</code> should return true.');"
],
"challengeSeed": [
"function meetBonfire(argument) {",
@ -28,6 +28,9 @@
"",
"meetBonfire(\"You can do this!\");"
],
"solutions": [
"function meetBonfire(argument) {\n // Good luck!\n console.log(\"you can read this function's argument in the developer tools\", argument);\n\n return true;\n}\n\n\n\nmeetBonfire(\"You can do this!\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -44,25 +47,24 @@
{
"id": "a202eed8fc186c8434cb6d61",
"title": "Reverse a String",
"difficulty": "1.01",
"tests": [
"expect(reverseString('hello')).to.be.a('String');",
"expect(reverseString('hello')).to.equal('olleh');",
"expect(reverseString('Howdy')).to.equal('ydwoH');",
"expect(reverseString('Greetings from Earth')).to.equal('htraE morf sgniteerG');"
"assert(typeof(reverseString(\"hello\")) === \"string\", 'message: <code>reverseString()</code> should return a string.');",
"assert(reverseString(\"hello\") === \"olleh\", 'message: <code>reverseString(\"hello\")</code> should become <code>\"olleh\"</code>.');",
"assert(reverseString(\"Howdy\") === \"ydwoH\", 'message: <code>reverseString(\"Howdy\")</code> should become <code>\"ydwoH\"</code>.');",
"assert(reverseString(\"Greetings from Earth\") === \"htraE morf sgniteerG\", 'message: <code>reverseString(\"Greetings from Earth\")</code> should return <code>\"htraE morf sgniteerG\"</code>.');"
],
"description": [
"Reverse the provided string.",
"You may need to turn the string into an array before you can reverse it.",
"Your result must be a string.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function reverseString(str) {",
" return str;",
"}",
"",
"reverseString('hello');"
"reverseString(\"hello\");"
],
"MDNlinks": [
"Global String Object",
@ -70,6 +72,9 @@
"Array.reverse()",
"Array.join()"
],
"solutions": [
"function reverseString(str) {\n return str.split('').reverse().join(\"\");\n}\n\nreverseString('hello');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -87,18 +92,18 @@
"id": "a302f7aae1aa3152a5b413bc",
"title": "Factorialize a Number",
"tests": [
"expect(factorialize(5)).to.be.a(\"Number\");",
"expect(factorialize(5)).to.equal(120);",
"expect(factorialize(10)).to.equal(3628800);",
"expect(factorialize(20)).to.equal(2432902008176640000);"
"assert(typeof(factorialize(5)) === \"number\", 'message: <code>factorialize()</code> should return a number.');",
"assert(factorialize(5) === 120, 'message: <code>factorialize(5)</code> should return 120.');",
"assert(factorialize(10) === 3628800, 'message: <code>factorialize(10)</code> should return 3628800.');",
"assert(factorialize(20) === 2432902008176640000, 'message: <code>factorialize(20)</code> should return 2432902008176640000.');",
"assert(factorialize(0) === 1, 'message: <code>factorialize(0)</code> should return 1.');"
],
"difficulty": "1.02",
"description": [
"Return the factorial of the provided integer.",
"If the integer is represented with the letter n, a factorial is the product of all positive integers less than or equal to n.",
"Factorials are often represented with the shorthand notation n!",
"For example: 5! = 1 * 2 * 3 * 4 * 5 = 120f",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Factorials are often represented with the shorthand notation <code>n!</code>",
"For example: <code>5! = 1 * 2 * 3 * 4 * 5 = 120</code>",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function factorialize(num) {",
@ -110,6 +115,9 @@
"MDNlinks": [
"Arithmetic Operators"
],
"solutions": [
"function factorialize(num) {\n return num === 1 ? 1 : num * factorialize(num-1);\n}\n\nfactorialize(5);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -126,23 +134,25 @@
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Check for Palindromes",
"difficulty": "1.03",
"description": [
"Return true if the given string is a palindrome. Otherwise, return false.",
"A palindrome is a word or sentence that's spelled the same way both forward and backward, ignoring punctuation, case, and spacing.",
"You'll need to remove punctuation and turn everything lower case in order to check for palindromes.",
"We'll pass strings with varying formats, such as \"racecar\", \"RaceCar\", and \"race CAR\" among others.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"tests": [
"expect(palindrome(\"eye\")).to.be.a(\"boolean\");",
"assert.deepEqual(palindrome(\"eye\"), true);",
"assert.deepEqual(palindrome(\"race car\"), true);",
"assert.deepEqual(palindrome(\"not a palindrome\"), false);",
"assert.deepEqual(palindrome(\"A man, a plan, a canal. Panama\"), true);",
"assert.deepEqual(palindrome(\"never odd or even\"), true);",
"assert.deepEqual(palindrome(\"nope\"), false);",
"assert.deepEqual(palindrome(\"almostomla\"), false);"
"assert(typeof(palindrome(\"eye\")) === \"boolean\", 'message: <code>palindrome()</code> should return a boolean.');",
"assert(palindrome(\"eye\") === true, 'message: <code>palindrome(\"eye\")</code> should return true.');",
"assert(palindrome(\"race car\") === true, 'message: <code>palindrome(\"race car\")</code> should return true.');",
"assert(palindrome(\"not a palindrome\") === false, 'message: <code>palindrome(\"not a palindrome\")</code> should return false.');",
"assert(palindrome(\"A man, a plan, a canal. Panama\") === true, 'message: <code>palindrome(\"A man, a plan, a canal. Panama\")</code> should return true.');",
"assert(palindrome(\"never odd or even\") === true, 'message: <code>palindrome(\"never odd or even\")</code> should return true.');",
"assert(palindrome(\"nope\") === false, 'message: <code>palindrome(\"nope\")</code> should return false.');",
"assert(palindrome(\"almostomla\") === false, 'message: <code>palindrome(\"almostomla\")</code> should return false.');",
"assert(palindrome(\"My age is 0, 0 si ega ym.\") === true, 'message: <code>palindrome(\"My age is 0, 0 si ega ym.\")</code> should return true.');",
"assert(palindrome(\"1 eye for of 1 eye.\") === false, 'message: <code>palindrome(\"1 eye for of 1 eye.\")</code> should return false.');",
"assert(palindrome(\"0_0 (: /-\\ :) 0-0\") === true, 'message: <code>palindrome(\"0_0 (: /-\\ :) 0-0\")</code> should return true.');"
],
"challengeSeed": [
"function palindrome(str) {",
@ -158,6 +168,9 @@
"String.replace()",
"String.toLowerCase()"
],
"solutions": [
"function palindrome(str) {\n var a = str.toLowerCase().replace(/[^a-z]/g, '');\n console.log(a.split('').reverse().join(''));\n return a == a.split('').reverse().join('');\n}\n\n\n\npalindrome(\"eye\");\npalindrome(\"A man, a plan, a canal. Panama\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -174,31 +187,33 @@
{
"id": "a26cbbe9ad8655a977e1ceb5",
"title": "Find the Longest Word in a String",
"difficulty": "1.04",
"description": [
"Return the length of the longest word in the provided sentence.",
"Your response should be a number.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function findLongestWord(str) {",
" return str.length;",
"}",
"",
"findLongestWord('The quick brown fox jumped over the lazy dog');"
"findLongestWord(\"The quick brown fox jumped over the lazy dog\");"
],
"tests": [
"expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.be.a('Number');",
"expect(findLongestWord('The quick brown fox jumped over the lazy dog')).to.equal(6);",
"expect(findLongestWord('May the force be with you')).to.equal(5);",
"expect(findLongestWord('Google do a barrel roll')).to.equal(6);",
"expect(findLongestWord('What is the average airspeed velocity of an unladen swallow')).to.equal(8);",
"expect(findLongestWord('What if we try a super-long word such as otorhinolaryngology')).to.equal(19);"
"assert(typeof(findLongestWord(\"The quick brown fox jumped over the lazy dog\")) === \"number\", 'message: <code>findLongestWord()</code> should return a number.');",
"assert(findLongestWord(\"The quick brown fox jumped over the lazy dog\") === 6, 'message: <code>findLongestWord(\"The quick brown fox jumped over the lazy dog\")</code> should return 6.');",
"assert(findLongestWord(\"May the force be with you\") === 5, 'message: <code>findLongestWord(\"May the force be with you\")</code> should return 5.');",
"assert(findLongestWord(\"Google do a barrel roll\") === 6, 'message: <code>findLongestWord(\"Google do a barrel roll\")</code> should return 6.');",
"assert(findLongestWord(\"What is the average airspeed velocity of an unladen swallow\") === 8, 'message: <code>findLongestWord(\"What is the average airspeed velocity of an unladen swallow\")</code> should return 8.');",
"assert(findLongestWord(\"What if we try a super-long word such as otorhinolaryngology\") === 19, 'message: <code>findLongestWord(\"What if we try a super-long word such as otorhinolaryngology\")</code> should return 19.');"
],
"MDNlinks": [
"String.split()",
"String.length"
],
"solutions": [
"function findLongestWord(str) {\n return str.split(' ').sort(function(a, b) { return b.length - a.length;})[0].length;\n}\n\nfindLongestWord('The quick brown fox jumped over the lazy dog');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -215,11 +230,10 @@
{
"id": "ab6137d4e35944e21037b769",
"title": "Title Case a Sentence",
"difficulty": "1.05",
"description": [
"Return the provided string with the first letter of each word capitalized.",
"For the purpose of this exercise, you should also capitalize connecting words like 'the' and 'of'.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Return the provided string with the first letter of each word capitalized. Make sure the rest of the word is in lower case.",
"For the purpose of this exercise, you should also capitalize connecting words like \"the\" and \"of\".",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function titleCase(str) {",
@ -229,14 +243,17 @@
"titleCase(\"I'm a little tea pot\");"
],
"tests": [
"expect(titleCase(\"I'm a little tea pot\")).to.be.a('String');",
"expect(titleCase(\"I'm a little tea pot\")).to.equal(\"I'm A Little Tea Pot\");",
"expect(titleCase(\"sHoRt AnD sToUt\")).to.equal(\"Short And Stout\");",
"expect(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\")).to.equal(\"Here Is My Handle Here Is My Spout\");"
"assert(typeof(titleCase(\"I&#39;m a little tea pot\")) === \"string\", 'message: <code>titleCase()</code> should return a string.');",
"assert(titleCase(\"I&#39;m a little tea pot\") === \"I&#39;m A Little Tea Pot\", 'message: <code>titleCase(\"I&#39;m a little tea pot\")</code> should return \"I&#39;m A Little Tea Pot\".');",
"assert(titleCase(\"sHoRt AnD sToUt\") === \"Short And Stout\", 'message: <code>titleCase(\"sHoRt AnD sToUt\")</code> should return \"Short And Stout\".');",
"assert(titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\") === \"Here Is My Handle Here Is My Spout\", 'message: <code>titleCase(\"HERE IS MY HANDLE HERE IS MY SPOUT\")</code> should return \"Here Is My Handle Here Is My Spout\".');"
],
"MDNlinks": [
"String.charAt()"
],
"solutions": [
"function titleCase(str) {\n return str.split(' ').map(function(word) {\n return word.charAt(0).toUpperCase() + word.substring(1).toLowerCase();\n }).join(' ');\n}\n\ntitleCase(\"I'm a little tea pot\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -253,12 +270,11 @@
{
"id": "a789b3483989747d63b0e427",
"title": "Return Largest Numbers in Arrays",
"difficulty": "1.06",
"description": [
"Return an array consisting of the largest number from each provided sub-array. For simplicity, the provided array will contain exactly 4 sub-arrays.",
"Remember, you can iterate through an array with a simple for loop, and access each member with array syntax arr[i] .",
"If you are writing your own Chai.js tests, be sure to use a deep equal statement instead of an equal statement when comparing arrays.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function largestOfFour(arr) {",
@ -269,13 +285,16 @@
"largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);"
],
"tests": [
"expect(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]])).to.be.a('array');",
"(largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]])).should.eql([27,5,39,1001]);",
"assert(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]).should.eql([9,35,97,1000000]));"
"assert(largestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]).constructor === Array, 'message: <code>largestOfFour()</code> should return an array.');",
"assert.deepEqual(largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]]), [27,5,39,1001], 'message: <code>largestOfFour([[13, 27, 18, 26], [4, 5, 1, 3], [32, 35, 37, 39], [1000, 1001, 857, 1]])</code> should return <code>[27,5,39,1001]</code>.');",
"assert.deepEqual(largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]]), [9,35,97,1000000], 'message: <code>largestOfFour([[4, 9, 1, 3], [13, 35, 18, 26], [32, 35, 97, 39], [1000000, 1001, 857, 1]])</code> should return <code>[9, 35, 97, 1000000]</code>.');"
],
"MDNlinks": [
"Comparison Operators"
],
"solutions": [
"function largestOfFour(arr) {\n return arr.map(function(subArr) {\n return Math.max.apply(null, subArr);\n });\n}\n\nlargestOfFour([[4, 5, 1, 3], [13, 27, 18, 26], [32, 35, 37, 39], [1000, 1001, 857, 1]]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -292,10 +311,9 @@
{
"id": "acda2fb1324d9b0fa741e6b5",
"title": "Confirm the Ending",
"difficulty": "1.07",
"description": [
"Check if a string (first argument) ends with the given target string (second argument).",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function end(str, target) {",
@ -304,18 +322,22 @@
" return str;",
"}",
"",
"end('Bastian', 'n');"
"end(\"Bastian\", \"n\");"
],
"tests": [
"assert.strictEqual(end('Bastian', 'n'), true, 'should equal true if target equals end of string');",
"assert.strictEqual(end('Connor', 'n'), false, 'should equal false if target does not equal end of string');",
"assert.strictEqual(end('Walking on water and developing software from a specification are easy if both are frozen.', 'specification'), false, 'should equal false if target does not equal end of string');",
"assert.strictEqual(end('He has to give me a new name', 'name'), true, 'should equal true if target equals end of string');",
"assert.strictEqual(end('If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing', 'mountain'), false, 'should equal false if target does not equal end of string');"
"assert(end(\"Bastian\", \"n\") === true, 'message: <code>end(\"Bastian\", \"n\")</code> should return true.');",
"assert(end(\"Connor\", \"n\") === false, 'message: <code>end(\"Connor\", \"n\")</code> should return false.');",
"assert(end(\"Walking on water and developing software from a specification are easy if both are frozen\", \"specification\") === false, '<code>\"Walking on water and developing software from a specification are easy if both are frozen\"&#44; \"specification\"&#41;</code> should return false.');",
"assert(end(\"He has to give me a new name\", \"name\") === true, 'message: <code>end(\"He has to give me a new name\", \"name\")</code> should return true.');",
"assert(end(\"He has to give me a new name\", \"me\") === true, 'message: <code>end(\"He has to give me a new name\", \"me\")</code> should return true.');",
"assert(end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\") === false, 'message: <code>end(\"If you want to save our world, you must hurry. We dont know how much longer we can withstand the nothing\", \"mountain\")</code> should return false.');"
],
"MDNlinks": [
"String.substr()"
],
"solutions": [
"function end(str, target) {\n // \"Never give up and good luck will find you.\"\n // -- Falcor\n return str.substring(str.length-target.length) === target;\n}\n\nend('Bastian', 'n');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -332,10 +354,9 @@
{
"id": "afcc8d540bea9ea2669306b6",
"title": "Repeat a string repeat a string",
"difficulty": "1.08",
"description": [
"Repeat a given string (first argument) n times (second argument). Return an empty string if n is a negative number.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function repeat(str, num) {",
@ -343,16 +364,19 @@
" return str;",
"}",
"",
"repeat('abc', 3);"
"repeat(\"abc\", 3);"
],
"tests": [
"assert.strictEqual(repeat('*', 3), '***', 'should repeat a string n times');",
"assert.strictEqual(repeat('abc', 3), 'abcabcabc', 'should repeat a string n times');",
"assert.strictEqual(repeat('abc', -2), '', 'should return an empty string for negative numbers');"
"assert(repeat(\"*\", 3) === \"***\", 'message: <code>repeat(\"*\", 3)</code> should return <code>\"***\"</code>.');",
"assert(repeat(\"abc\", 3) === \"abcabcabc\", 'message: <code>repeat(\"abc\", 3)</code> should return <code>\"abcabcabc\"</code>.');",
"assert(repeat(\"abc\", -2) === \"\", 'message: <code>repeat(\"abc\", -2)</code> should return <code>\"\"</code>.');"
],
"MDNlinks": [
"Global String Object"
],
"solutions": [
"function repeat(str, num) {\n if (num < 0) return '';\n return num === 1 ? str : str + repeat(str, num-1);\n}\n\nrepeat('abc', 3);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -369,11 +393,11 @@
{
"id": "ac6993d51946422351508a41",
"title": "Truncate a string",
"difficulty": "1.09",
"description": [
"Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a '...' ending.",
"Truncate a string (first argument) if it is longer than the given maximum string length (second argument). Return the truncated string with a \"...\" ending.",
"Note that the three dots at the end add to the string length.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"If the length of the string is less than or equal to 3 characters, then the length of the three dots is not added to the string length.",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function truncate(str, num) {",
@ -381,17 +405,21 @@
" return str;",
"}",
"",
"truncate('A-tisket a-tasket A green and yellow basket', 11);"
"truncate(\"A-tisket a-tasket A green and yellow basket\", 11);"
],
"tests": [
"expect(truncate('A-tisket a-tasket A green and yellow basket', 11)).to.eqls('A-tisket...');",
"expect(truncate('Peter Piper picked a peck of pickled peppers', 14)).to.eqls('Peter Piper...');",
"assert(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length) === 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is = length');",
"assert.strictEqual(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length + 2), 'A-tisket a-tasket A green and yellow basket', 'should not truncate if string is < length');"
"assert(truncate(\"A-tisket a-tasket A green and yellow basket\", 11) === \"A-tisket...\", 'message: <code>truncate(\"A-tisket a-tasket A green and yellow basket\", 11)</code> should return \"A-tisket...\".');",
"assert(truncate(\"Peter Piper picked a peck of pickled peppers\", 14) === \"Peter Piper...\", 'message: <code>truncate(\"Peter Piper picked a peck of pickled peppers\", 14)</code> should return \"Peter Piper...\".');",
"assert(truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length) === \"A-tisket a-tasket A green and yellow basket\", 'message: <code>truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length)</code> should return \"A-tisket a-tasket A green and yellow basket\".');",
"assert(truncate('A-tisket a-tasket A green and yellow basket', 'A-tisket a-tasket A green and yellow basket'.length + 2) === 'A-tisket a-tasket A green and yellow basket', 'message: <code>truncate(\"A-tisket a-tasket A green and yellow basket\", \"A-tisket a-tasket A green and yellow basket\".length + 2)</code> should return \"A-tisket a-tasket A green and yellow basket\".');",
"assert(truncate(\"A-\", 1) === \"A...\", 'message: <code>truncate(\"A-\", 1)</code> should return \"A...\".');"
],
"MDNlinks": [
"String.slice()"
],
"solutions": [
"function truncate(str, num) {\n if (str.length > num) {\n return str.substring(0, num-3) + '...';\n }\n return str;\n}\n\ntruncate('A-tisket a-tasket A green and yellow basket', 11);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -408,10 +436,9 @@
{
"id": "a9bd25c716030ec90084d8a1",
"title": "Chunky Monkey",
"difficulty": "1.10",
"description": [
"Write a function that splits an array (first argument) into groups the length of size (second argument) and returns them as a multidimensional array.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function chunk(arr, size) {",
@ -419,17 +446,20 @@
" return arr;",
"}",
"",
"chunk(['a', 'b', 'c', 'd'], 2);"
"chunk([\"a\", \"b\", \"c\", \"d\"], 2);"
],
"tests": [
"assert.deepEqual(chunk(['a', 'b', 'c', 'd'], 2), [['a', 'b'], ['c', 'd']], 'should return chunked arrays');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'should return chunked arrays');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 2), [[0, 1], [2, 3], [4, 5]], 'should return chunked arrays');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'should return the last chunk as remaining elements');"
"assert.deepEqual(chunk([\"a\", \"b\", \"c\", \"d\"], 2), [[\"a\", \"b\"], [\"c\", \"d\"]], 'message: <code>chunk([\"a\", \"b\", \"c\", \"d\"], 2)</code> should return <code>[[\"a\", \"b\"], [\"c\", \"d\"]]</code>.');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 3), [[0, 1, 2], [3, 4, 5]], 'message: <code>chunk([0, 1, 2, 3, 4, 5], 3)</code> should return <code>[[0, 1, 2], [3, 4, 5]]</code>.');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 2), [[0, 1], [2, 3], [4, 5]], 'message: <code>chunk([0, 1, 2, 3, 4, 5], 2)</code> should return <code>[[0, 1], [2, 3], [4, 5]]</code>.');",
"assert.deepEqual(chunk([0, 1, 2, 3, 4, 5], 4), [[0, 1, 2, 3], [4, 5]], 'message: <code>chunk([0, 1, 2, 3, 4, 5], 4)</code> should return <code>[[0, 1, 2, 3], [4, 5]]</code>.');"
],
"MDNlinks": [
"Array.push()"
],
"solutions": [
"function chunk(arr, size) {\n var out = [];\n for (var i = 0; i < arr.length; i+=size) {\n out.push(arr.slice(i,i+size));\n }\n return out;\n}\n\nchunk(['a', 'b', 'c', 'd'], 2);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -446,10 +476,10 @@
{
"id": "ab31c21b530c0dafa9e241ee",
"title": "Slasher Flick",
"difficulty": "1.11",
"description": [
"Return the remaining elements of an array after chopping off n elements from the head.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"The head meaning the beginning of the array, or the zeroth index",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function slasher(arr, howMany) {",
@ -460,14 +490,18 @@
"slasher([1, 2, 3], 2);"
],
"tests": [
"assert.deepEqual(slasher([1, 2, 3], 2), [3], 'should drop the first two elements');",
"assert.deepEqual(slasher([1, 2, 3], 0), [1, 2, 3], 'should return all elements');",
"assert.deepEqual(slasher([1, 2, 3], 9), [], 'should return an empty array');"
"assert.deepEqual(slasher([1, 2, 3], 2), [3], 'message: <code>slasher([1, 2, 3], 2)</code> should return <code>[3]</code>.');",
"assert.deepEqual(slasher([1, 2, 3], 0), [1, 2, 3], 'message: <code>slasher([1, 2, 3], 0)</code> should return <code>[1, 2, 3]</code>.');",
"assert.deepEqual(slasher([1, 2, 3], 9), [], 'message: <code>slasher([1, 2, 3], 9)</code> should return <code>[]</code>.');",
"assert.deepEqual(slasher([1, 2, 3], 4), [], 'message: <code>slasher([1, 2, 3], 4)</code> should return <code>[]</code>.');"
],
"MDNlinks": [
"Array.slice()",
"Array.splice()"
],
"solutions": [
"function slasher(arr, howMany) {\n // it doesn't always pay to be first\n return arr.slice(howMany);\n}\n\nslasher([1, 2, 3], 2);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -484,34 +518,36 @@
{
"id": "af2170cad53daa0770fabdea",
"title": "Mutations",
"difficulty": "1.12",
"description": [
"Return true if the string in the first element of the array contains all of the letters of the string in the second element of the array.",
"For example, ['hello', 'Hello'], should return true because all of the letters in the second string are present in the first, ignoring case.",
"The arguments ['hello', 'hey'] should return false because the string 'hello' does not contain a 'y'.",
"Lastly, ['Alien', 'line'], should return true because all of the letters in 'line' are present in 'Alien'.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"For example, <code>[\"hello\", \"Hello\"]</code>, should return true because all of the letters in the second string are present in the first, ignoring case.",
"The arguments <code>[\"hello\", \"hey\"]</code> should return false because the string \"hello\" does not contain a \"y\".",
"Lastly, <code>[\"Alien\", \"line\"]</code>, should return true because all of the letters in \"line\" are present in \"Alien\".",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function mutation(arr) {",
" return arr;",
"}",
"",
"mutation(['hello', 'hey']);"
"mutation([\"hello\", \"hey\"]);"
],
"tests": [
"expect(mutation(['hello', 'hey'])).to.be.false;",
"expect(mutation(['hello', 'Hello'])).to.be.true;",
"expect(mutation(['zyxwvutsrqponmlkjihgfedcba', 'qrstu'])).to.be.true;",
"expect(mutation(['Mary', 'Army'])).to.be.true;",
"expect(mutation(['Mary', 'Aarmy'])).to.be.true;",
"expect(mutation(['Alien', 'line'])).to.be.true;",
"expect(mutation(['floor', 'for'])).to.be.true;",
"expect(mutation(['hello', 'neo'])).to.be.false;"
"assert(mutation([\"hello\", \"hey\"]) === false, 'message: <code>mutation([\"hello\", \"hey\"])</code> should return false.');",
"assert(mutation([\"hello\", \"Hello\"]) === true, 'message: <code>mutation([\"hello\", \"Hello\"])</code> should return true.');",
"assert(mutation([\"zyxwvutsrqponmlkjihgfedcba\", \"qrstu\"]) === true, 'message: <code>mutation([\"zyxwvutsrqponmlkjihgfedcba\", \"qrstu\"])</code> should return true.');",
"assert(mutation([\"Mary\", \"Army\"]) === true, 'message: <code>mutation([\"Mary\", \"Army\"])</code> should return true.');",
"assert(mutation([\"Mary\", \"Aarmy\"]) === true, 'message: <code>mutation([\"Mary\", \"Aarmy\"])</code> should return true.');",
"assert(mutation([\"Alien\", \"line\"]) === true, 'message: <code>mutation([\"Alien\", \"line\"])</code> should return true.');",
"assert(mutation([\"floor\", \"for\"]) === true, 'message: <code>mutation([\"floor\", \"for\"])</code> should return true.');",
"assert(mutation([\"hello\", \"neo\"]) === false, 'message: <code>mutation([\"hello\", \"neo\"])</code> should return false.');"
],
"MDNlinks": [
"Array.indexOf()"
],
"solutions": [
"function mutation(arr) {\n var hash = Object.create(null);\n arr[0].toLowerCase().split('').forEach(function(c) {\n hash[c] = true;\n });\n return !arr[1].toLowerCase().split('').filter(function(c) {\n return !hash[c];\n }).length;\n}\n\nmutation(['hello', 'hey']);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -527,12 +563,11 @@
},
{
"id": "adf08ec01beb4f99fc7a68f2",
"title": "Falsey Bouncer",
"difficulty": "1.50",
"title": "Falsy Bouncer",
"description": [
"Remove all falsey values from an array.",
"Falsey values in javascript are false, null, 0, \"\", undefined, and NaN.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remove all falsy values from an array.",
"Falsy values in javascript are <code>false</code>, <code>null</code>, <code>0</code>, <code>\"\"</code>, <code>undefined</code>, and <code>NaN</code>.",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function bouncer(arr) {",
@ -540,58 +575,19 @@
" return arr;",
"}",
"",
"bouncer([7, 'ate', '', false, 9]);"
"bouncer([7, \"ate\", \"\", false, 9]);"
],
"tests": [
"assert.deepEqual(bouncer([7, 'ate', '', false, 9]), [7, 'ate', 9], 'should remove falsey values');",
"assert.deepEqual(bouncer(['a', 'b', 'c']), ['a', 'b', 'c'], 'should return full array if no falsey elements');",
"assert.deepEqual(bouncer([false, null, 0]), [], 'should return empty array if all elements are falsey');"
"assert.deepEqual(bouncer([7, \"ate\", \"\", false, 9]), [7, \"ate\", 9], 'message: <code>bouncer([7, \"ate\", \"\", false, 9])</code> should return <code>[7, \"ate\", 9]</code>.');",
"assert.deepEqual(bouncer([\"a\", \"b\", \"c\"]), [\"a\", \"b\", \"c\"], 'message: <code>bouncer([\"a\", \"b\", \"c\"])</code> should return <code>[\"a\", \"b\", \"c\"]</code>.');",
"assert.deepEqual(bouncer([false, null, 0, NaN, undefined, \"\"]), [], 'message: <code>bouncer([false, null, 0, NaN, undefined, \"\"])</code> should return <code>[]</code>.');"
],
"MDNlinks": [
"Boolean Objects",
"Array.filter()"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "a8e512fbe388ac2f9198f0fa",
"title": "Where art thou",
"difficulty": "1.55",
"description": [
"Make a function that looks through an array (first argument) and returns an array of all objects that have equivalent property and value pair (second argument).",
"For example, if the first argument is <code>[{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }]</code>, and the second argument is <code>{ last: 'Capulet' }</code>, then you must return the the third object from the array (the first argument), because it contains the property and it's value, that was passed on as the second argument.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function where(collection, source) {",
" var arr = [];",
" // What's in a name?",
" return arr;",
"}",
"",
"where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });"
],
"tests": [
"assert.deepEqual(where([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' }), [{ first: 'Tybalt', last: 'Capulet' }], 'should return an array of objects');",
"assert.deepEqual(where([{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], { 'a': 1 }), [{ 'a': 1 }, { 'a': 1 }, { 'a': 1, 'b': 2 }], 'should return with multiples');",
"assert.deepEqual(where([{ 'a': 1, 'b': 2 }, { 'a': 1 }, { 'a': 1, 'b': 2, 'c': 2 }], { 'a': 1, 'b': 2 }), [{ 'a': 1, 'b': 2 }, { 'a': 1, 'b': 2, 'c': 2 }], 'should return two objects in array');",
"assert.deepEqual(where([{ 'a': 5 }, { 'a': 5 }, { 'a': 5, 'b': 10 }], { 'a': 5, 'b': 10 }), [{ 'a': 5, 'b': 10 }], 'should return a single object in array');"
],
"MDNlinks": [
"Global Object",
"Object.hasOwnProperty()",
"Object.keys()"
"solutions": [
"function bouncer(arr) {\n // Don't show a false ID to this bouncer.\n return arr.filter(function(e) {return e;});\n}\n\nbouncer([7, 'ate', '', false, 9]);\n"
],
"type": "bonfire",
"challengeType": 5,
@ -609,10 +605,9 @@
{
"id": "a39963a4c10bc8b4d4f06d7e",
"title": "Seek and Destroy",
"difficulty": "1.60",
"description": [
"You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function destroyer(arr) {",
@ -623,16 +618,19 @@
"destroyer([1, 2, 3, 1, 2, 3], 2, 3);"
],
"tests": [
"assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'should remove correct values from an array');",
"assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'should remove correct values from an array');",
"assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], 'should accept more than two additional arguments');",
"assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], 'should remove correct values from an array');",
"assert.deepEqual(destroyer(['tree', 'hamburger', 53], 'tree', 53), ['hamburger'], 'should handle NaN-elements');"
"assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1], 'message: <code>destroyer([1, 2, 3, 1, 2, 3], 2, 3)</code> should return <code>[1, 1]</code>.');",
"assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1], 'message: <code>destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3)</code> should return <code>[1, 5, 1]</code>.');",
"assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1], 'message: <code>destroyer([3, 5, 1, 2, 2], 2, 3, 5)</code> should return <code>[1]</code>.');",
"assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), [], 'message: <code>destroyer([2, 3, 2, 3], 2, 3)</code> should return <code>[]</code>.');",
"assert.deepEqual(destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53), [\"hamburger\"], 'message: <code>destroyer([\"tree\", \"hamburger\", 53], \"tree\", 53)</code> should return <code>[\"hamburger\"]</code>.');"
],
"MDNlinks": [
"Arguments object",
"Array.filter()"
],
"solutions": [
"function destroyer(arr) {\n var hash = Object.create(null);\n [].slice.call(arguments, 1).forEach(function(e) {\n hash[e] = true;\n });\n // Remove all the values\n return arr.filter(function(e) { return !(e in hash);});\n}\n\ndestroyer([1, 2, 3, 1, 2, 3], 2, 3);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -649,11 +647,11 @@
{
"id": "a24c1a4622e3c05097f71d67",
"title": "Where do I belong",
"difficulty": "1.61",
"description": [
"Return the lowest index at which a value (second argument) should be inserted into a sorted array (first argument).",
"For example, where([1,2,3,4], 1.5) should return 1 because it is greater than 1 (0th index), but less than 2 (1st index).",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
"Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted.",
"For example, where([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1).",
"Likewise, where([20,3,5], 19) should return 2 because it is less than 20 (index 2) and greater than 5 (index 1).",
"Remember to use <a href=\"//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck\" target=\"_blank\">Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function where(arr, num) {",
@ -666,9 +664,16 @@
"MDNlinks": [
"Array.sort()"
],
"solutions": [
"function where(arr, num) {\n // Find my place in this sorted array.\n return num;\n}\n\nwhere([40, 60], 50);\n"
],
"tests": [
"expect(where([10, 20, 30, 40, 50], 35)).to.equal(3);",
"expect(where([10, 20, 30, 40, 50], 30)).to.equal(2);"
"assert(where([10, 20, 30, 40, 50], 35) === 3, 'message: <code>where([10, 20, 30, 40, 50], 35)</code> should return <code>3</code>.');",
"assert(where([10, 20, 30, 40, 50], 30) === 2, 'message: <code>where([10, 20, 30, 40, 50], 30)</code> should return <code>2</code>.');",
"assert(where([40, 60], 50) === 1, 'message: <code>where([40, 60,], 50)</code> should return <code>1</code>.');",
"assert(where([5, 3, 20, 3], 5) === 2, 'message: <code>where([5, 3, 20, 3], 5)</code> should return <code>2</code>.');",
"assert(where([2, 20, 10], 19) === 2, 'message: <code>where([2, 20, 10], 19)</code> should return <code>2</code>.');",
"assert(where([2, 5, 10], 15) === 3, 'message: <code>where([2, 5, 10], 15)</code> should return <code>3</code>.');"
],
"type": "bonfire",
"challengeType": 5,

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +1,46 @@
{
"name": "Basic Front End Development Projects",
"order": 0.008,
"order": 9,
"time": "100h",
"challenges": [
{
"id": "bd7158d8c442eddfbeb5bd1f",
"title": "Get Set for Ziplines",
"difficulty": 1.00,
"challengeSeed": ["125658022"],
"challengeSeed": [],
"description": [
"Now you're ready to start our Zipline challenges. These front-end development challenges will give you many opportunities to apply the HTML, CSS, jQuery and JavaScript you've learned to build static (database-less) applications.",
"Whatever you do, don't get discouraged! Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck.",
"We'll build these challenges using CodePen, a popular tool for creating, sharing, and discovering static web applications.",
"Go to <a href='http://codepen.io' target='_blank'>http://codepen.io</a> and create an account.",
"Click your user image in the top right corner, then click the \"New pen\" button that drops down.",
"Drag the windows around and press the buttons in the lower-right hand corner to change the orientation to suit your preference.",
"Click the gear next to CSS. Then under the \"Add External CSS\" section, use the \"Quick-add\" select box to select Bootstrap. Then click \"Save & Close\".",
"Verify that bootstrap is active by adding the following code to your HTML: <code>&lt;h1 class='text-primary'&gt;Hello CodePen!&lt;/h1&gt;</code>. The text's color should be Bootstrap blue.",
"Click the gear next to JavaScript. Click the \"Quick-add\" select box and choose jQuery (not jQuery UI). Then click \"Save & Close\".",
"Now add the following code to your JavaScript: <code>$(document).ready(function() { $('.text-primary').text('Hi CodePen!') });</code>. Click the \"Save\" button at the top. Your \"Hello CodePen!\" should change to \"Hi CodePen!\". This means that jQuery is working.",
"You can use this CodePen that you've just created as a starting point for your Ziplines. Just click the \"fork\" button at the top of your CodePen and it will create a duplicate CodePen.",
"Now you're ready for your first Zipline. Click the \"I've completed this challenge\" button."
[
"http://i.imgur.com/6WLULsC.gif",
"A gif showing how to create a Codepen account.",
"For our front end Zipline challenges, we'll use a popular browser-based code editor called CodePen. Open CodePen and click \"Sign up\" in the upper right hand corner, then scroll down to the free plan and click \"Sign up\" again. Click the \"Use info from GitHub button\", then add your email address and create a password. Click the \"Sign up\" button. Then in the upper right hand corner, click \"New pen\".",
"http://codepen.io"
],
"type": "waypoint",
"challengeType": 2,
[
"http://i.imgur.com/U4y9RJ1.gif",
"A gif showing that you can type \"hello world\" will output \"hello world\" in the preview window. You can also drag windows to resize them, and change their orientation.",
"In the HTML box, create an h1 element with the text \"Hello World\". You can drag the frames around to resize them. You can also click the \"Change View\" button and change the orientation of the frames.",
""
],
[
"http://i.imgur.com/G9KFQDL.gif",
"A gif showing the process of adding Bootstrap to your pen.",
"Click the gear in the upper left hand corner of the CSS box, then scroll down to \"Quick add\" and choose Bootstrap. Now give your h1 element the class of \"text-primary\" to change its color and prove that Bootstrap is now available.",
""
],
[
"http://i.imgur.com/Gi3aig0.gif",
"A gif showing the process of adding Animate.css and jQuery to pen.",
"Click the gear in the upper left hand corner of the CSS box, then scroll down to \"Quick add\" and choose Animate.css. Click the gear in the upper left hand corner of the JS box, then scroll down to \"Quick add\" and choose jQuery. Let's prove that Animate.css and jQuery are loaded properly. In the JS box, add the following code to make your h1 element bounce: <code>$(document).ready(function(){ $(\"h1\").addClass(\"animated bounce\"); });</code>.",
""
],
[
"http://i.imgur.com/Wzt6Y9Y.gif",
"A gif showing the process of saving and forking a pen.",
"Save your pen with the \"Save\" button. Then click the \"Fork\" button. This will create a fork (copy) of your pen that you can experiment with.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
@ -38,7 +56,6 @@
{
"id": "bd7158d8c242eddfaeb5bd13",
"title": "Build a Personal Portfolio Webpage",
"difficulty": 1.01,
"challengeSeed": ["133315782"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/ThiagoFerreir4/full/eNMxEp' target='_blank'>http://codepen.io/ThiagoFerreir4/full/eNMxEp</a>.",
@ -51,12 +68,12 @@
"<span class='text-info'>User Story:</span> As a user, I can click different buttons that will take me to the portfolio creator's different social media pages.",
"<span class='text-info'>User Story:</span> As a user, I can see thumbnail images of different projects the portfolio creator has built (if you haven't built any websites before, use placeholders.)",
"<span class='text-info'>Bonus User Story:</span> As a user, I navigate to different sections of the webpage by clicking buttons in the navigation.",
"Don't worry if you don't have anything to showcase on your portfolio yet - you will build several several apps on the next few CodePen challenges, and can come back and update your portfolio later.",
"Don't worry if you don't have anything to showcase on your portfolio yet - you will build several apps on the next few CodePen challenges, and can come back and update your portfolio later.",
"There are many great portfolio templates out there, but for this challenge, you'll need to build a portfolio page yourself. Using Bootstrap will make this much easier for you.",
"Note that CodePen.io overrides the Window.open() function, so if you want to open windows using jquery, you will need to target invisible anchor elements like this one: <code>&lt;a target='_blank'&gt;</a></code>.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -65,8 +82,25 @@
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameRu": "Создайте сайт-портфолио",
"descriptionRu": [
"<span class='text-info'>Задание:</span> Создайте <a href='http://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='http://codepen.io/ThiagoFerreir4/full/eNMxEp' target='_blank'>http://codepen.io/ThiagoFerreir4/full/eNMxEp</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"<span class='text-info'>Подсказка:</span> Если вы не хотите создавать портфолио с нуля, можете взять за основу этот простой Bootstrap шаблон: <a href='http://codepen.io/FreeCodeCamp/pen/mJNqQj/' target='_blank'>http://codepen.io/FreeCodeCamp/pen/mJNqQj</a>.",
"Реализуйте следующие <a href='http://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> В качестве пользователя, я могу перемещаться к различным частям страницы нажимая на соответствующие навигационные кнопки.",
"Не переживайте если вам пока нечего показать в портфолио - вы создадите несколько веб приложений в следующих заданиях, а затем вернетесь и обновите портфолио.",
"В сети существует много шаблонов для портфолио, но в этом задании вам необходимо создать собственную уникальную страницу. Использование Bootstrap сделает этот процесс намного проще.",
"Обратите внимание, что CodePen.io переопределяет функцию Window.open(), поэтому, если вы хотите открывать окна используя jQuery, необходимо будет адресовать невидимые якорные элементы, такие как этот: <code>&lt;a target='_blank'&rt;</a></code>.",
"Если что-то не получается, воспользуйтесь <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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>"
],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
@ -75,7 +109,6 @@
{
"id": "bd7158d8c442eddfaeb5bd13",
"title": "Build a Random Quote Machine",
"difficulty": 1.02,
"challengeSeed": ["126415122"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/AdventureBear/full/vEoVMw' target='_blank'>http://codepen.io/AdventureBear/full/vEoVMw</a>.",
@ -85,10 +118,9 @@
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can click a button to show me a new random quote.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can press a button to tweet out a quote.",
"Note that you can either put your quotes into an array and show them at random, or use an API to get quotes, such as <a href='http://forismatic.com/en/api/'>http://forismatic.com/en/api/</a>.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -97,41 +129,20 @@
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c442eddfaeb5bd10",
"title": "Show the Local Weather",
"difficulty": 1.03,
"challengeSeed": ["126415127"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/AdventureBear/full/yNBJRj' target='_blank'>http://codepen.io/AdventureBear/full/yNBJRj</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can see the weather in my current location.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can see an icon depending on the temperature..",
"<span class='text-info'>Bonus User Story:</span> As a user, I see a different background image depending on the temperature (e.g. snowy mountain, hot desert).",
"<span class='text-info'>Bonus User Story:</span> As a user, I can push a button to toggle between Fahrenheit and Celsius.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"nameRu": "Создайте генератор случайных цитат",
"descriptionRu": [
"<span class='text-info'>Задание:</span> Создайте <a href='http://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='http://codepen.io/AdventureBear/full/vEoVMw' target='_blank'>http://codepen.io/AdventureBear/full/vEoVMw</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу нажать на кнопку и получить случайную цитату.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу нажать на кнопку и опубликовать цитату в Twitter'e.",
"Цитаты можно добавить в массив и случайным образом выводить одну из них, либо можно воспользоваться соответствующим API, например <a href='http://forismatic.com/en/api/'>http://forismatic.com/en/api/</a>.",
"Если что-то не получается, воспользуйтесь <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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>"
],
"type": "zipline",
"challengeType": 3,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
@ -140,7 +151,6 @@
{
"id": "bd7158d8c442eddfaeb5bd0f",
"title": "Build a Pomodoro Clock",
"difficulty": 1.04,
"challengeSeed": ["126411567"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/RPbGxZ/' target='_blank'>http://codepen.io/GeoffStorbeck/full/RPbGxZ/</a>.",
@ -153,7 +163,7 @@
"<span class='text-info'>Bonus User Story:</span> As a user, I can customize the length of each pomodoro.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -162,35 +172,41 @@
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameRu": "Создайте таймер Pomodoro",
"descriptionRu": [
"<span class='text-info'>Задание:</span> Создайте <a href='http://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='http://codepen.io/GeoffStorbeck/full/RPbGxZ/' target='_blank'>http://codepen.io/GeoffStorbeck/full/RPbGxZ/</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу запустить 25 минутную 'помидорку', по истечении которой таймер выключится.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу сбросить таймер для установки следующей 'помидорки'.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу выбирать длительность 'помидорки'.",
"Если что-то не получается, воспользуйтесь <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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>"
],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c442eddfaeb5bd1f",
"title": "Use the Twitch.tv JSON API",
"difficulty": 1.05,
"challengeSeed": ["126411564"],
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator",
"challengeSeed": ["126411565"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/GJKRxZ' target='_blank'>http://codepen.io/GeoffStorbeck/full/GJKRxZ</a>.",
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/zxgaqw' target='_blank'>http://codepen.io/GeoffStorbeck/full/zxgaqw</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can see whether Free Code Camp is currently streaming on Twitch.tv.",
"<span class='text-info'>User Story:</span> As a user, I can click the status output and be sent directly to the Free Code Camp's Twitch.tv channel.",
"<span class='text-info'>User Story:</span> As a user, if Free Code Camp is streaming, I can see additional details about what they are streaming.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can search through the streams listed.",
"<span class='text-info'>Bonus User Story:</span> As a user, I will see a placeholder notification if a streamer has closed their Twitch account. You can verify this works by adding brunofin and comster404 to your array of Twitch streamers.",
"<span class='text-info'>Hint:</span> Here's an example call to Twitch.tv's JSON API: <code>https://api.twitch.tv/kraken/streams/freecodecamp</code>.",
"<span class='text-info'>Hint:</span> The relevant documentation about this API call is here: <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'>Hint:</span> Here's an array of the Twitch.tv usernames of people who regularly stream coding: <code>[\"freecodecamp\", \"storbeck\", \"terakilobyte\", \"habathcx\",\"RobotCaleb\",\"thomasballinger\",\"noobs2ninjas\",\"beohoff\"]</code>",
"<span class='text-info'>User Story:</span> As a user, I can add, subtract, multiply and divide two numbers.",
"<span class='text-info'>Bonus User Story:</span> I can clear the input field with a clear button.",
"<span class='text-info'>Bonus User Story:</span> I can keep chaining mathematical operations together until I hit the equal button, and the calculator will tell me the correct output.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,

View File

@ -1,21 +1,24 @@
{
"name": "Responsive Design with Bootstrap",
"order": 0.003,
"order": 3,
"time": "2h",
"challenges": [
{
"id": "bad87fee1348bd9acde08712",
"title": "Use Responsive Design with Bootstrap Fluid Containers",
"difficulty": 2.01,
"description": [
"Now let's go back to our Cat Photo App. This time, we'll style it using the popular Bootstrap responsive CSS framework.",
"Bootstrap will figure out how wide your screen is and respond by resizing your HTML elements - hence the name <code>Responsive Design</code>.",
"With responsive design, there is no need to design a mobile version of your website. It will look good on devices with screens of any width.",
"You can add Bootstrap to any app just by including it with <code>&#60;link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css\"/&#62;</code> at the top of your HTML. But we've gone ahead and automatically added it to your Cat Photo App for you.",
"You can add Bootstrap to any app just by including it by adding the following code to the top of your HTML:",
"<code>&#60;link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css\"/&#62;</code>",
"In this case, we've already added it for you to this page behind the scenes.",
"To get started, we should nest all of our HTML in a <code>div</code> element with the class <code>container-fluid</code>."
],
"tests": [
"assert($(\"div\").hasClass(\"container-fluid\"), 'Your <code>div</code> element should have the class <code>container-fluid</code>')",
"assert(editor.match(/<\\/div>/g) && editor.match(/<div/g) && editor.match(/<\\/div>/g).length === editor.match(/<div/g).length, 'Make sure each of your <code>div</code> elements has a closing tag.')"
"assert($(\"div\").hasClass(\"container-fluid\"), 'Your <code>div</code> element should have the class <code>container-fluid</code>.')",
"assert(editor.match(/<\\/div>/g) && editor.match(/<div/g) && editor.match(/<\\/div>/g).length === editor.match(/<div/g).length, 'Make sure each of your <code>div</code> elements has a closing tag.')",
"assert($(\".container-fluid\").children().length >= 8, 'Make sure you have nested all HTML elements in <code>.container-fluid</code>.')"
],
"challengeSeed": [
"<link href=\"http://fonts.googleapis.com/css?family=Lobster\" rel=\"stylesheet\" type=\"text/css\">",
@ -89,16 +92,16 @@
{
"id": "bad87fee1348bd9acde08812",
"title": "Make Images Mobile Responsive",
"difficulty": 2.02,
"description": [
"First, Add a new image below the existing one. Set it's <code>src</code> attribute to <code>http://bit.ly/fcc-running-cats</code>.",
"First, add a new image below the existing one. Set its <code>src</code> attribute to <code>http://bit.ly/fcc-running-cats</code>.",
"It would be great if this image could be exactly the width of our phone's screen.",
"Fortunately, with Bootstrap, all we need to do is add the <code>img-responsive</code> class to your image. Do this, and the image should perfectly fit the width of your page."
],
"tests": [
"assert($(\"img\").length > 1, 'You should have a total of two images.')",
"assert($(\"img\").hasClass(\"img-responsive\"), 'Your new image should have the class <code>img-responsive</code>.')",
"assert(new RegExp(\"http://bit.ly/fcc-running-cats\", \"gi\").test($(\"img.img-responsive\").attr(\"src\")), 'Add a second image with the <code>src</code> of <code>http&#58;//bit.ly/fcc-running-cats</code>.')"
"assert($(\"img\").length === 2, 'You should have a total of two images.')",
"assert($(\"img:eq(1)\").hasClass(\"img-responsive\"), 'Your new image should be below your old one and have the class <code>img-responsive</code>.')",
"assert($(\"img:eq(1)\").attr(\"src\") === \"http://bit.ly/fcc-running-cats\", 'Your new image should have a <code>src</code> of <code>http&#58;//bit.ly/fcc-running-cats</code>.')",
"assert(editor.match(/<img/g) && editor.match(/<img.*>/g).length === 2 && editor.match(/<img/g).length === 2, 'Make sure your new <code>img</code> element has a closing angle bracket.')"
],
"challengeSeed": [
"<link href=\"http://fonts.googleapis.com/css?family=Lobster\" rel=\"stylesheet\" type=\"text/css\">",
@ -174,10 +177,10 @@
{
"id": "bad87fee1348bd8acde08812",
"title": "Center Text with Bootstrap",
"difficulty": 2.03,
"description": [
"Now that we're using Bootstrap, we can center our heading element to make it look better. All we need to do is add the class <code>text-center</code> to our <code>h2</code> element.",
"Remember that you can add several classes to the same element by separating each of them with a space, like this: <code>&#60h2 class=\"red-text text-center\"&#62your text&#60/h2&#62</code>."
"Remember that you can add several classes to the same element by separating each of them with a space, like this:",
"<code>&#60h2 class=\"red-text text-center\"&#62your text&#60/h2&#62</code>"
],
"tests": [
"assert($(\"h2\").hasClass(\"text-center\"), 'Your <code>h2</code> element should be centered by applying the class <code>text-center</code>')"
@ -257,7 +260,6 @@
{
"id": "bad87fee1348cd8acdf08812",
"title": "Create a Bootstrap Button",
"difficulty": 2.04,
"description": [
"Bootstrap has its own styles for <code>button</code> elements, which look much better than the plain HTML ones.",
"Create a new <code>button</code> element below your large kitten photo. Give it the class <code>btn</code> and the text of \"Like\"."
@ -343,11 +345,10 @@
{
"id": "bad87fee1348cd8acef08812",
"title": "Create a Block Element Bootstrap Button",
"difficulty": 2.05,
"description": [
"Normally, your <code>button</code> elements are only as wide as the text that they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space.",
"Normally, your <code>button</code> elements are only as wide as the text that they contain. By making them block elements, your button will stretch to fill your page's entire horizontal space and any elements following it will flow onto a \"new line\" below the block.",
"This image illustrates the difference between <code>inline</code> elements and <code>block-level</code> elements:",
"<img class=\"img-responsive\" src=\"http://i.imgur.com/O32cDWE.png\" alt=\"An \"inline\" button is as small as the text it contains. In this image, it's centered. Below it is a \"block-level\" button, which stretches to fill the entire horizontal space.'>",
"<a href=\"http://i.imgur.com/O32cDWE.png\" data-lightbox=\"img-enlarge\"><img class=\"img-responsive\" src=\"http://i.imgur.com/O32cDWE.png\" title=\"Click to enlarge\" alt=\"An \"inline\" button is as small as the text it contains. In this image, it's centered. Below it is a \"block-level\" button, which stretches to fill the entire horizontal space.'></a>",
"Note that these buttons still need the <code>btn</code> class.",
"Add Bootstrap's <code>btn-block</code> class to your Bootstrap button."
],
@ -432,7 +433,6 @@
{
"id": "bad87fee1348cd8acef08811",
"title": "Taste the Bootstrap Button Color Rainbow",
"difficulty": 2.06,
"description": [
"The <code>btn-primary</code> class is the main color you'll use in your app. It is useful for highlighting actions you want your user to take.",
"Add Bootstrap's <code>btn-primary</code> class to your button.",
@ -519,7 +519,6 @@
{
"id": "bad87fee1348cd8acef08813",
"title": "Call out Optional Actions with Button Info",
"difficulty": 2.07,
"description": [
"Bootstrap comes with several pre-defined colors for buttons. The <code>btn-info</code> class is used to call attention to optional actions that the user can take.",
"Create a new block-level Bootstrap button below your \"Like\" button with the text \"Info\", and add Bootstrap's <code>btn-info</code> and <code>btn-block</code> classes to it.",
@ -607,7 +606,6 @@
{
"id": "bad87fee1348ce8acef08814",
"title": "Warn your Users of a Dangerous Action",
"difficulty": 2.08,
"description": [
"Bootstrap comes with several pre-defined colors for buttons. The <code>btn-danger</code> class is the button color you'll use to notify users that the button performs a destructive action, such as deleting a cat photo.",
"Create a button with the text \"Delete\" and give it the class <code>btn-danger</code>.",
@ -696,11 +694,10 @@
{
"id": "bad88fee1348ce8acef08815",
"title": "Use the Bootstrap Grid to Put Elements Side By Side",
"difficulty": 2.09,
"description": [
"Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a <code>div</code> element.",
"Here's a diagram of how Bootstrap's 12-column grid layout works:",
"<a href=\"http://i.imgur.com/FaYuui8.png\" target=\"_blank\"><img class=\"img-responsive\" src=\"http://i.imgur.com/FaYuui8.png\" alt=\"an image illustrating Bootstrap's grid system\"></a>",
"<a href=\"http://i.imgur.com/FaYuui8.png\" data-lightbox=\"img-enlarge\"><img class=\"img-responsive\" src=\"http://i.imgur.com/FaYuui8.png\" title=\"Click to enlarge\" alt=\"an image illustrating Bootstrap's grid system\"></a>",
"Note that in this illustration, the <code>col-md-*</code> class is being used. Here, <code>md</code> means medium, and <code>*</code> is a number specifying how many columns wide the element should be. In this case, the column width of an element on a medium-sized screen, such as a laptop, is being specified.",
"In the Cat Photo App that we're building, we'll use <code>col-xs-*</code>, where <code>xs</code> means extra small (like an extra-small mobile phone screen), and <code>*</code> is the number of columns specifying how many columns wide the element should be.",
"Put the <code>Like</code>, <code>Info</code> and <code>Delete</code> buttons side-by-side by nesting all three of them within one <code>&#60;div class=\"row\"&#62;</code> element, then each of them within a <code>&#60;div class=\"col-xs-4\"&#62;</code> element.",
@ -790,7 +787,6 @@
{
"id": "bad87fee1347bd9aedf08845",
"title": "Ditch Custom CSS for Bootstrap",
"difficulty": 2.10,
"description": [
"We can clean up our code and make our Cat Photo App look more conventional by using Bootstrap's built-in styles instead of the custom styles we created earlier.",
"Don't worry - there will be plenty of time to customize our CSS later.",
@ -891,14 +887,14 @@
{
"id": "bad87fee1348bd9aedf08845",
"title": "Use Spans for Inline Elements",
"difficulty": 2.105,
"description": [
"You can use spans to create inline elements. Remember when we used the <code>btn-block</code> class to make the button fill the entire row?",
"This image illustrates the difference between <code>inline</code> elements and <code>block-level</code> elements:",
"<img class=\"img-responsive\" src=\"http://i.imgur.com/O32cDWE.png\" alt=\"An \"inline\" button is as small as the text it contains. In this image, it's centered. Below it is a \"block-level\" button, which stretches to fill the entire horizontal space.'>",
"<a href=\"http://i.imgur.com/O32cDWE.png\" data-lightbox=\"img-enlarge\"><img class=\"img-responsive\" src=\"http://i.imgur.com/O32cDWE.png\" title=\"Click to enlarge\" alt=\"An \"inline\" button is as small as the text it contains. In this image, it's centered. Below it is a \"block-level\" button, which stretches to fill the entire horizontal space.'></a>",
"By using the <code>span</code> element, you can put several elements together, and even style different parts of the same element differently.",
"Nest the word \"love\" in your \"Things cats love\" element below within a <code>span</code> element. Then give that <code>span</code> the class <code>text-danger</code> to make the text red.",
"Here's how you would do this with the \"Top 3 things cats hate\" element: <code>&#60;p&#62;Top 3 things cats &#60;span class = \"text-danger\"&#62;hate&#60;/span&#62;&#60;/p&#62;</code>"
"Here's how you would do this with the \"Top 3 things cats hate\" element:",
"<code>&#60;p&#62;Top 3 things cats &#60;span class = \"text-danger\"&#62;hate&#60;/span&#62;&#60;/p&#62;</code>"
],
"tests": [
"assert($(\"p span\") && $(\"p span\").length > 0, 'Your <code>span</code> element should be inside your <code>p</code> element.')",
@ -909,19 +905,11 @@
"challengeSeed": [
"<link href=\"http://fonts.googleapis.com/css?family=Lobster\" rel=\"stylesheet\" type=\"text/css\">",
"<style>",
" .red-text {",
" color: red;",
" }",
"",
" h2 {",
" font-family: Lobster, Monospace;",
" }",
"",
" p {",
" font-size: 16px;",
" font-family: Monospace;",
" }",
"",
" .thick-green-border {",
" border-color: green;",
" border-width: 10px;",
@ -929,17 +917,12 @@
" border-radius: 50%;",
" }",
"",
" .smaller-image {",
" width: 100px;",
" }",
"</style>",
"",
"<div class=\"container-fluid\">",
" <h2 class=\"red-text text-center\">CatPhotoApp</h2>",
" <h2 class=\"text-primary text-center\">CatPhotoApp</h2>",
"",
" <p>Click here for <a href=\"#\">cat photos</a>.</p>",
"",
" <a href=\"#\"><img class=\"smaller-image thick-green-border\" src=\"https://bit.ly/fcc-relaxing-cat\"></a>",
" <a href=\"#\"><img class=\"img-responsive thick-green-border\" src=\"https://bit.ly/fcc-relaxing-cat\"></a>",
"",
" <img src=\"http://bit.ly/fcc-running-cats\" class=\"img-responsive\">",
" <div class=\"row\">",
@ -992,12 +975,11 @@
{
"id": "bad87fee1348bd9aede08845",
"title": "Create a Custom Heading",
"difficulty": 2.11,
"description": [
"We will make a simple heading for our Cat Photo App by putting them in the same row.",
"Remember, Bootstrap uses a responsive grid system, which makes it easy to put elements into rows and specify each element's relative width. Most of Bootstrap's classes can be applied to a <code>div</code> element.",
"Here's a diagram of how Bootstrap's 12-column grid layout works:",
"<a href=\"http://i.imgur.com/FaYuui8.png\" target=\"_blank\"><img class=\"img-responsive\" src=\"http://i.imgur.com/FaYuui8.png\" alt=\"an image illustrating Bootstrap's grid system\"></a>",
"<a href=\"http://i.imgur.com/FaYuui8.png\" data-lightbox=\"img-enlarge\"><img class=\"img-responsive\" src=\"http://i.imgur.com/FaYuui8.png\" title=\"Click to enlarge\" alt=\"an image illustrating Bootstrap's grid system\"></a>",
"Note that in this illustration, the <code>col-md-*</code> class is being used. Here, <code>md</code> means medium, and <code>*</code> is a number specifying how many columns wide the element should be. In this case, the column width of an element on a medium-sized screen, such as a laptop, is being specified.",
"In the Cat Photo App that we're building, we'll use <code>col-xs-*</code>, where <code>xs</code> means extra small (like an extra-small mobile phone screen), and <code>*</code> is the number of columns specifying how many columns wide the element should be.",
"Nest your first image and your <code>h2</code> element within a single <code>&#60;div class=\"row\"&#62;</code> element. Nest your <code>h2</code> text within a <code>&#60;div class=\"col-xs-8\"&#62;</code> and your image in a <code>&#60;div class=\"col-xs-4\"&#62;</code> so that they are on the same line.",
@ -1081,7 +1063,6 @@
{
"id": "bad87fee1348bd9aedd08845",
"title": "Add Font Awesome Icons to our Buttons",
"difficulty": 2.12,
"description": [
"Font Awesome is a convenient library of icons. These icons are vector graphics, stored in the <code>.svg</code> file format. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements.",
"Use Font Awesome to add a <code>thumbs-up</code> icon to your like button by giving it a <code>i</code> element with the classes <code>fa</code> and <code>fa-thumbs-up</code>."
@ -1166,15 +1147,14 @@
{
"id": "bad87fee1348bd9aedc08845",
"title": "Add Font Awesome Icons to all of our Buttons",
"difficulty": 2.13,
"description": [
"Font Awesome is a convenient library of icons. These icons are vector graphics, stored in the <code>.svg</code> file format. These icons are treated just like fonts. You can specify their size using pixels, and they will assume the font size of their parent HTML elements.",
"Use Font Awesome to add a <code>info-circle</code> icon to your info button and a <code>trash</code> icon to your delete button."
],
"tests": [
"assert($(\"i\").hasClass(\"fa fa-trash\"), 'You should add a <code>&#60;i class=\"fa fa-trash\"&#62;&#60;/i&#62;</code> within your delete button element.')",
"assert($(\"i\").hasClass(\"fa fa-info-circle\"), 'You should add a <code>&#60;i class=\"fa fa-info-circle\"&#62;&#60;/i&#62;</code> within your info button element.')",
"assert(editor.match(/<\\/i>/g) && editor.match(/<\\/i/g).length > 2, 'Make sure each of your <code>i</code> elements has a closing tag.')"
"assert($(\".btn-danger > i\").hasClass(\"fa fa-trash\"), 'You should add a <code>&#60;i class=\"fa fa-trash\"&#62;&#60;/i&#62;</code> within your delete button element.')",
"assert($(\".btn-info > i\").hasClass(\"fa fa-info-circle\"), 'You should add a <code>&#60;i class=\"fa fa-info-circle\"&#62;&#60;/i&#62;</code> within your info button element.')",
"assert(editor.match(/<\\/i>/g) && editor.match(/<\\/i>/g).length > 2 && $(\".btn-primary > i\").hasClass(\"fa fa-thumbs-up\"), 'Make sure each of your <code>i</code> elements has a closing tag and <code>&#60;i class=\"fa fa-thumbs-up\"&#62;&#60;/i&#62;</code> is in your like button element.')"
],
"challengeSeed": [
"<link href=\"http://fonts.googleapis.com/css?family=Lobster\" rel=\"stylesheet\" type=\"text/css\">",
@ -1251,7 +1231,6 @@
{
"id": "bad87fee1348bd9aedb08845",
"title": "Responsively Style Radio Buttons",
"difficulty": 2.14,
"description": [
"You can use Bootstrap's <code>col-xs-*</code> classes on <code>form</code> elements, too! This way, our radio buttons will be evenly spread out across the page, regardless of how wide the screen resolution is.",
"Nest all of your radio buttons within a <code>&#60;div class=\"row\"&#62;</code> element. Then nest each of them within a <code>&#60;div class=\"col-xs-6\"&#62;</code> element."
@ -1336,7 +1315,6 @@
{
"id": "bad87fee1348bd9aeda08845",
"title": "Responsively Style Checkboxes",
"difficulty": 2.15,
"description": [
"You can use Bootstrap's <code>col-xs-*</code> classes on <code>form</code> elements, too! This way, our checkboxes will be evenly spread out across the page, regardless of how wide the screen resolution is.",
"Nest all your checkboxes in a <code>&#60;div class=\"row\"&#62;</code> element. Then nest each of them in a <code>&#60;div class=\"col-xs-4\"&#62;</code> element."
@ -1428,7 +1406,6 @@
{
"id": "bad87fee1348bd9aed908845",
"title": "Style Text Inputs as Form Controls",
"difficulty": 2.16,
"description": [
"You can add the <code>fa-paper-plane</code> Font Awesome icon by adding <code>&#60;i class=\"fa fa-paper-plane\"&#62;&#60;/i&#62;</code> within your submit <code>button</code> element.",
"Give your form's text input field a class of <code>form-control</code>. Give your form's submit button the classes <code>btn btn-primary</code>. Also give this button the Font Awesome icon of <code>fa-paper-plane</code>."
@ -1529,7 +1506,6 @@
{
"id": "bad87fee1348bd9aec908845",
"title": "Line up Form Elements Responsively with Bootstrap",
"difficulty": 2.17,
"description": [
"Now let's get your form <code>input</code> and your submission <code>button</code> on the same line. We'll do this the same way we have previously: by using a <code>div</code> element with the class <code>row</code>, and other <code>div</code> elements within it using the <code>col-xs-*</code> class.",
"Nest both your form's text <code>input</code> and submit <code>button</code> within a <code>div</code> with the class <code>row</code>. Nest your form's text <code>input</code> within a div with the class of <code>col-xs-7</code>. Nest your form's submit <code>button</code> in a <code>div</code> with the class <code>col-xs-5</code>.",
@ -1631,7 +1607,6 @@
{
"id": "bad87fee1348bd9aec908846",
"title": "Create a Bootstrap Headline",
"difficulty": 2.18,
"description": [
"Now let's build something from scratch to practice our HTML, CSS and Bootstrap skills.",
"We'll build a jQuery playground, which we'll soon put to use in our jQuery challenges.",
@ -1666,7 +1641,6 @@
{
"id": "bad87fee1348bd9aec908746",
"title": "House our page within a Bootstrap Container Fluid Div",
"difficulty": 2.18,
"description": [
"Now let's make sure all the content on your page is mobile-responsive.",
"Let's nest your <code>h3</code> element within a <code>div</code> element with the class <code>container-fluid</code>."
@ -1696,7 +1670,6 @@
{
"id": "bad87fee1348bd9bec908846",
"title": "Create a Bootstrap Row",
"difficulty": 2.19,
"description": [
"Now we'll create a Bootstrap row for our inline elements.",
"Create a <code>div</code> element with the class <code>row</code>."
@ -1729,13 +1702,12 @@
{
"id": "bad87fee1348bd9aec908847",
"title": "Split your Bootstrap Row",
"difficulty": 2.20,
"description": [
"Now that we have a Bootstrap Row, let's split it into two columns to house our elements.",
"Create two <code>div</code> elements within your row, both with the class <code>col-xs-6</code>."
],
"tests": [
"assert($(\"div.row\").children(\"div.col-xs-6\").length > 1, 'Nest two <code>div class=\"col-xs-6\"</code> elements within your <code>div class=\"row\"</code> element.')",
"assert($(\"div.row > div.col-xs-6\").length > 1, 'Nest two <code>div class=\"col-xs-6\"</code> elements within your <code>div class=\"row\"</code> element.')",
"assert(editor.match(/<\\/div>/g) && editor.match(/<div/g) && editor.match(/<\\/div>/g).length === editor.match(/<div/g).length, 'Make sure all your <code>div</code> elements have closing tags.')"
],
"challengeSeed": [
@ -1763,14 +1735,13 @@
{
"id": "bad87fee1348bd9aec908848",
"title": "Create Bootstrap Wells",
"difficulty": 2.21,
"description": [
"Bootstrap has a class called <code>well</code> that can create a visual sense of depth for your columns.",
"Nest one <code>div</code> element with the class <code>well</code> within each of your <code>col-xs-6</code> <code>div</code> elements."
],
"tests": [
"assert($(\"div\").length > 4, 'Add a <code>div</code> element with the class <code>well</code> inside each of your <code>div class=\"col-xs-6\"> elements</code>')",
"assert($(\"div.col-xs-6 div.well\").length > 1, 'Nest both of your <code>div class=\"col-xs-6\"</code> elements within your <code>div class=\"row\"</code> element.')",
"assert($(\"div.col-xs-6\").not(\":has(>div.well)\").length < 1, 'Add a <code>div</code> element with the class <code>well</code> inside each of your <code>div</code> elements with the class <code>\"col-xs-6\"</code>')",
"assert($(\"div.row > div.col-xs-6\").length > 1, 'Nest both of your <code>div</code> elements with the class <code>\"col-xs-6\"</code> within your <code>div</code> element with the class <code>\"row\"</code>.')",
"assert(editor.match(/<\\/div>/g) && editor.match(/<div/g) && editor.match(/<\\/div>/g).length === editor.match(/<div/g).length, 'Make sure all your <code>div</code> elements have closing tags.')"
],
"challengeSeed": [
@ -1802,7 +1773,6 @@
{
"id": "bad87fee1348bd9aec908849",
"title": "Add Elements within your Bootstrap Wells",
"difficulty": 2.22,
"description": [
"Now we're several <code>div</code> elements deep on each column of our row. This is as deep as we'll need to go. Now we can add our <code>button</code> elements.",
"Nest three <code>button</code> elements within each of your <code>well</code> <code>div</code> elements."
@ -1849,7 +1819,6 @@
{
"id": "bad87fee1348bd9aec908850",
"title": "Apply the Default Bootstrap Button Style",
"difficulty": 2.23,
"description": [
"Bootstrap has another button class called <code>btn-default</code>.",
"Apply both the <code>btn</code> and <code>btn-default</code> classes to each of your <code>button</code> elements."
@ -1895,7 +1864,6 @@
{
"id": "bad87fee1348bd9aec908852",
"title": "Create a Class to Target with jQuery Selectors",
"difficulty": 2.24,
"description": [
"Not every class needs to have corresponding CSS. Sometimes we create classes just for the purpose of selecting these elements more easily using jQuery.",
"Give each of your <code>button</code> elements the class <code>target</code>."
@ -1940,17 +1908,17 @@
{
"id": "bad87fee1348bd9aec908853",
"title": "Add ID Attributes to Bootstrap Elements",
"difficulty": 2.25,
"description": [
"Recall that in addition to class attributes, you can give each of your elements an <code>id</code> attribute.",
"Each id should be unique to a specific element.",
"Each id must be unique to a specific element and used only once per page.",
"Let's give a unique id to each of our <code>div</code> elements of class <code>well</code>.",
"Remember that you can give an element an id like this: <code>&#60;div class=\"well\" id=\"center-well\"&#62;</code>",
"Remember that you can give an element an id like this:",
"<code>&#60;div class=\"well\" id=\"center-well\"&#62;</code>",
"Give the well on the left the id of <code>left-well</code>. Give the well on the right the <code>id</code> of <code>right-well</code>."
],
"tests": [
"assert($(\"#left-well\") && $(\"#left-well\").length > 0, 'Give your left <code>well</code> the id of <code>left-well</code>.')",
"assert($(\"#right-well\") && $(\"#right-well\").length > 0, 'Give your right <code>well</code> the id of <code>right-well</code>.')"
"assert($(\".col-xs-6\").children(\"#left-well\") && $(\".col-xs-6\").children(\"#left-well\").length > 0, 'Give your left <code>well</code> the id of <code>left-well</code>.')",
"assert($(\".col-xs-6\").children(\"#right-well\") && $(\".col-xs-6\").children(\"#right-well\").length > 0, 'Give your right <code>well</code> the id of <code>right-well</code>.')"
],
"challengeSeed": [
"<div class=\"container-fluid\">",
@ -1989,14 +1957,13 @@
{
"id": "bad87fee1348bd9aec908854",
"title": "Label Bootstrap Wells",
"difficulty": 2.26,
"description": [
"For the sake of clarity, let's label both of our wells with their ids.",
"Above your left-well, inside its <code>col-xs-6</code> <code>div</code> element, add a <code>h4</code> element with the text <code>#left-well</code>.",
"Above your right-well, inside its <code>col-xs-6</code> <code>div</code> element, add a <code>h4</code> element with the text <code>#right-well</code>."
],
"tests": [
"assert($(\".col-xs-6\").children(\"h4\") && $(\".col-xs-6\").children(\"h4\").length > 1, 'Add an <code>h4</code> element to each of your <code>&#60;div class=\\\"col-xs-6\\\"&#62;</code> elements.');",
"assert($(\".col-xs-6\").children(\"h4\") && $(\".col-xs-6\").children(\"h4\").length > 1, 'Add an <code>h4</code> element to each of your <code>&#60;div class=\"col-xs-6\"&#62;</code> elements.');",
"assert(new RegExp(\"#left-well\",\"gi\").test($(\"h4\").text()), 'One <code>h4</code> element should have the text <code>#left-well</code>.');",
"assert(new RegExp(\"#right-well\",\"gi\").test($(\"h4\").text()), 'One <code>h4</code> element should have the text <code>#right-well</code>.');",
"assert(editor.match(/<\\/h4>/g) && editor.match(/<h4/g) && editor.match(/<\\/h4>/g).length === editor.match(/<h4/g).length, 'Make sure all your <code>h4</code> elements have closing tags.')"
@ -2040,18 +2007,17 @@
{
"id": "bad87fee1348bd9aec908855",
"title": "Give Each Element a Unique ID",
"difficulty": 2.27,
"description": [
"We will also want to be able to use jQuery to target each button by its unique id.",
"Give each of your buttons a unique id like, starting with <code>target1</code> and ending with <code>target6</code>."
],
"tests": [
"assert($(\"#target1\") && $(\"#target1\").length > 0, 'One <code>button</code> element should have the id <code>target1</code>.')",
"assert($(\"#target2\") && $(\"#target2\").length > 0, 'One <code>button</code> element should have the id <code>target2</code>.')",
"assert($(\"#target3\") && $(\"#target3\").length > 0, 'One <code>button</code> element should have the id <code>target3</code>.')",
"assert($(\"#target4\") && $(\"#target4\").length > 0, 'One <code>button</code> element should have the id <code>target4</code>.')",
"assert($(\"#target5\") && $(\"#target5\").length > 0, 'One <code>button</code> element should have the id <code>target5</code>.')",
"assert($(\"#target6\") && $(\"#target6\").length > 0, 'One <code>button</code> element should have the id <code>target6</code>.')"
"assert($(\"#left-well\").children(\"#target1\") && $(\"#left-well\").children(\"#target1\").length > 0, 'One <code>button</code> element should have the id <code>target1</code>.')",
"assert($(\"#left-well\").children(\"#target2\") && $(\"#left-well\").children(\"#target2\").length > 0, 'One <code>button</code> element should have the id <code>target2</code>.')",
"assert($(\"#left-well\").children(\"#target3\") && $(\"#left-well\").children(\"#target3\").length > 0, 'One <code>button</code> element should have the id <code>target3</code>.')",
"assert($(\"#right-well\").children(\"#target4\") && $(\"#right-well\").children(\"#target4\").length > 0, 'One <code>button</code> element should have the id <code>target4</code>.')",
"assert($(\"#right-well\").children(\"#target5\") && $(\"#right-well\").children(\"#target5\").length > 0, 'One <code>button</code> element should have the id <code>target5</code>.')",
"assert($(\"#right-well\").children(\"#target6\") && $(\"#right-well\").children(\"#target6\").length > 0, 'One <code>button</code> element should have the id <code>target6</code>.')"
],
"challengeSeed": [
"<div class=\"container-fluid\">",
@ -2092,7 +2058,6 @@
{
"id": "bad87fee1348bd9aec908856",
"title": "Label Bootstrap Buttons",
"difficulty": 2.28,
"description": [
"Just like we labeled our wells, we want to label our buttons.",
"Give each of your <code>button</code> elements text that corresponds to their <code>id</code>."
@ -2144,17 +2109,16 @@
{
"id": "bad87fee1348bd9aec908857",
"title": "Use Comments to Clarify Code",
"difficulty": 2.29,
"description": [
"When we start using jQuery, we will modify HTML elements without needing to actually change them in HTML.",
"Let's make sure that everyone knows they shouldn't actually modify any of this code directly.",
"Remember that you can start a comment with <code>&#60;!--</code> and end a comment with <code>--&#62;</code>",
"Add a comment at the top of your HTML that says <code>You shouldn't need to modify code below this line</code>."
"Add a comment at the top of your HTML that says <code>Only change code above this line.</code>"
],
"tests": [
"assert(editor.match(/<!--/g) && editor.match(/<!--/g).length > 0, 'Start a comment with <code>&#60;!--</code>.')",
"assert(editor.match(/this line/g) && editor.match(/this line/g).length > 0, 'Your comment should have the text <code>You shouldn&#39;t need to modify code below this line</code>.')",
"assert(editor.match(/-->/g) && editor.match(/-->/g).length > 0, 'Be sure to close your comment with <code>--&#62;</code>.')"
"assert(editor.match(/this line/g) && editor.match(/this line/g).length > 0, 'Your comment should have the text <code>Only change code above this line</code>.')",
"assert(editor.match(/-->.*\\n+.+/g), 'Be sure to close your comment with <code>--&#62;</code>.')"
],
"challengeSeed": [
"<div class=\"container-fluid\">",

View File

@ -0,0 +1,250 @@
{
"name": "Claim Your Front End Development Certificate",
"order": 12,
"time": "5m",
"challenges": [
{
"id": "561add10cb82ac38a17513be",
"title": "Claim Your Front End Development Certificate",
"challengeSeed": [
{
"properties": ["isHonest", "isFrontEndCert"],
"apis": ["/certificate/honest", "/certificate/verify/front-end"],
"stepIndex": [1, 2]
}
],
"description": [
[
"http://i.imgur.com/syJxavV.jpg",
"An image of our Front End Development Certificate",
"This challenge will give you your verified Front End Development Certificate. Before we issue your certificate, we must verify that you have completed all of our basic and intermediate Bonfires, and all our basic and intermediate Ziplines. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"http://i.imgur.com/HArFfMN.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"http://i.imgur.com/14F2Van.jpg",
"An image of the text \"Front End Development Certificate requirements\"",
"Let's confirm that you have completed all of our basic and intermediate Bonfires, and all our basic and intermediate Ziplines. Click the button below to verify this.",
"#"
],
[
"http://i.imgur.com/16SIhHO.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Front End Development Certificate to your certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [
{
"id": "ad7123c8c441eddfaeb5bdef",
"title": "Meet Bonfire"
},
{
"id": "a202eed8fc186c8434cb6d61",
"title": "Reverse a String"
},
{
"id": "a302f7aae1aa3152a5b413bc",
"title": "Factorialize a Number"
},
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Check for Palindromes"
},
{
"id": "a26cbbe9ad8655a977e1ceb5",
"title": "Find the Longest Word in a String"
},
{
"id": "ab6137d4e35944e21037b769",
"title": "Title Case a Sentence"
},
{
"id": "a789b3483989747d63b0e427",
"title": "Return Largest Numbers in Arrays"
},
{
"id": "acda2fb1324d9b0fa741e6b5",
"title": "Confirm the Ending"
},
{
"id": "afcc8d540bea9ea2669306b6",
"title": "Repeat a string repeat a string"
},
{
"id": "ac6993d51946422351508a41",
"title": "Truncate a string"
},
{
"id": "a9bd25c716030ec90084d8a1",
"title": "Chunky Monkey"
},
{
"id": "ab31c21b530c0dafa9e241ee",
"title": "Slasher Flick"
},
{
"id": "af2170cad53daa0770fabdea",
"title": "Mutations"
},
{
"id": "adf08ec01beb4f99fc7a68f2",
"title": "Falsy Bouncer"
},
{
"id": "a39963a4c10bc8b4d4f06d7e",
"title": "Seek and Destroy"
},
{
"id": "a24c1a4622e3c05097f71d67",
"title": "Where do I belong"
},
{
"id": "a3566b1109230028080c9345",
"title": "Sum All Numbers in a Range"
},
{
"id": "a5de63ebea8dbee56860f4f2",
"title": "Diff Two Arrays"
},
{
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter"
},
{
"id": "a8e512fbe388ac2f9198f0fa",
"title": "Where art thou"
},
{
"id": "a0b5010f579e69b815e7c5d6",
"title": "Search and Replace"
},
{
"id": "aa7697ea2477d1316795783b",
"title": "Pig Latin"
},
{
"id": "afd15382cdfb22c9efe8b7de",
"title": "DNA Pairing"
},
{
"id": "af7588ade1100bde429baf20",
"title": "Missing letters"
},
{
"id": "a77dbc43c33f39daa4429b4f",
"title": "Boo who"
},
{
"id": "a105e963526e7de52b219be9",
"title": "Sorted Union"
},
{
"id": "a6b0bb188d873cb2c8729495",
"title": "Convert HTML Entities"
},
{
"id": "a103376db3ba46b2d50db289",
"title": "Spinal Tap Case"
},
{
"id": "a5229172f011153519423690",
"title": "Sum All Odd Fibonacci Numbers"
},
{
"id": "a3bfc1673c0526e06d3ac698",
"title": "Sum All Primes"
},
{
"id": "ae9defd7acaf69703ab432ea",
"title": "Smallest Common Multiple"
},
{
"id": "a6e40f1041b06c996f7b2406",
"title": "Finders Keepers"
},
{
"id": "a5deed1811a43193f9f1c841",
"title": "Drop it"
},
{
"id": "ab306dbdcc907c7ddfc30830",
"title": "Steamroller"
},
{
"id": "a8d97bd4c764e91f9d2bda01",
"title": "Binary Agents"
},
{
"id": "a10d2431ad0c6a099a4b8b52",
"title": "Everything Be True"
},
{
"id": "a97fd23d9b809dac9921074f",
"title": "Arguments Optional"
},
{
"id": "bd7158d8c442eddfbeb5bd1f",
"title": "Get Set for Ziplines"
},
{
"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.tv 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"
}
],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
}
]
}

View File

@ -0,0 +1,311 @@
{
"name": "Claim Your Full Stack Development Certificate",
"order": 21,
"time": "5m",
"challenges": [
{
"id": "660add10cb82ac38a17513be",
"title": "Claim Your Full Stack Development Certificate",
"difficulty": 0.00,
"challengeSeed": [
{
"properties": ["isHonest", "isFullStackCert"],
"apis": ["/certificate/honest", "/certificate/verify/full-stack"],
"stepIndex": [1, 2]
}
],
"description": [
[
"http://i.imgur.com/sKYQhdG.jpg",
"An image of our Full Stack Development Certificate",
"This challenge will give you your verified Full Stack Development Certificate. Before we issue your certificate, we must verify that you have completed all of Bonfires, Ziplines and Basejumps. You must also accept our Academic Honesty Pledge. Click the button below to start this process.",
""
],
[
"http://i.imgur.com/HArFfMN.jpg",
"The definition of plagiarism: Plagiarism (noun) - copying someone elses work and presenting it as your own without crediting them",
"By clicking below, you pledge that all of your submitted code A) is code you or your pair personally wrote, or B) comes from open source libraries like jQuery, or C) has been clearly attributed to its original authors. You also give us permission to audit your challenge solutions and revoke your certificate if we discover evidence of plagiarism.",
"#"
],
[
"http://i.imgur.com/2qn7tHp.jpg",
"An image of the text \"Full Stack Development Certificate requirements\"",
"Let's confirm that you have completed all of our Bonfires, Ziplines and Basejumps. Click the button below to verify this.",
"#"
],
[
"http://i.imgur.com/16SIhHO.jpg",
"An image of the word \"Congratulations\"",
"Congratulations! We've added your Full Stack Development Certificate to your certificate to your portfolio page. Unless you choose to hide your solutions, this certificate will remain publicly visible and verifiable.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [
{
"id": "ad7123c8c441eddfaeb5bdef",
"title": "Meet Bonfire"
},
{
"id": "a202eed8fc186c8434cb6d61",
"title": "Reverse a String"
},
{
"id": "a302f7aae1aa3152a5b413bc",
"title": "Factorialize a Number"
},
{
"id": "aaa48de84e1ecc7c742e1124",
"title": "Check for Palindromes"
},
{
"id": "a26cbbe9ad8655a977e1ceb5",
"title": "Find the Longest Word in a String"
},
{
"id": "ab6137d4e35944e21037b769",
"title": "Title Case a Sentence"
},
{
"id": "a789b3483989747d63b0e427",
"title": "Return Largest Numbers in Arrays"
},
{
"id": "acda2fb1324d9b0fa741e6b5",
"title": "Confirm the Ending"
},
{
"id": "afcc8d540bea9ea2669306b6",
"title": "Repeat a string repeat a string"
},
{
"id": "ac6993d51946422351508a41",
"title": "Truncate a string"
},
{
"id": "a9bd25c716030ec90084d8a1",
"title": "Chunky Monkey"
},
{
"id": "ab31c21b530c0dafa9e241ee",
"title": "Slasher Flick"
},
{
"id": "af2170cad53daa0770fabdea",
"title": "Mutations"
},
{
"id": "adf08ec01beb4f99fc7a68f2",
"title": "Falsy Bouncer"
},
{
"id": "a39963a4c10bc8b4d4f06d7e",
"title": "Seek and Destroy"
},
{
"id": "a24c1a4622e3c05097f71d67",
"title": "Where do I belong"
},
{
"id": "a3566b1109230028080c9345",
"title": "Sum All Numbers in a Range"
},
{
"id": "a5de63ebea8dbee56860f4f2",
"title": "Diff Two Arrays"
},
{
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter"
},
{
"id": "a8e512fbe388ac2f9198f0fa",
"title": "Where art thou"
},
{
"id": "a0b5010f579e69b815e7c5d6",
"title": "Search and Replace"
},
{
"id": "aa7697ea2477d1316795783b",
"title": "Pig Latin"
},
{
"id": "afd15382cdfb22c9efe8b7de",
"title": "DNA Pairing"
},
{
"id": "af7588ade1100bde429baf20",
"title": "Missing letters"
},
{
"id": "a77dbc43c33f39daa4429b4f",
"title": "Boo who"
},
{
"id": "a105e963526e7de52b219be9",
"title": "Sorted Union"
},
{
"id": "a6b0bb188d873cb2c8729495",
"title": "Convert HTML Entities"
},
{
"id": "a103376db3ba46b2d50db289",
"title": "Spinal Tap Case"
},
{
"id": "a5229172f011153519423690",
"title": "Sum All Odd Fibonacci Numbers"
},
{
"id": "a3bfc1673c0526e06d3ac698",
"title": "Sum All Primes"
},
{
"id": "ae9defd7acaf69703ab432ea",
"title": "Smallest Common Multiple"
},
{
"id": "a6e40f1041b06c996f7b2406",
"title": "Finders Keepers"
},
{
"id": "a5deed1811a43193f9f1c841",
"title": "Drop it"
},
{
"id": "ab306dbdcc907c7ddfc30830",
"title": "Steamroller"
},
{
"id": "a8d97bd4c764e91f9d2bda01",
"title": "Binary Agents"
},
{
"id": "a10d2431ad0c6a099a4b8b52",
"title": "Everything Be True"
},
{
"id": "a97fd23d9b809dac9921074f",
"title": "Arguments Optional"
},
{
"id": "bd7158d8c442eddfbeb5bd1f",
"title": "Get Set for Ziplines"
},
{
"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.tv 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"
},
{
"id": "a2f1d72d9b908d0bd72bb9f6",
"title": "Make a Person"
},
{
"id": "af4afb223120f7348cdfc9fd",
"title": "Map the Debris"
},
{
"id": "a3f503de51cfab748ff001aa",
"title": "Pairwise"
},
{
"id": "aff0395860f5d3034dc0bfc9",
"title": "Validate US Telephone Numbers"
},
{
"id": "a3f503de51cf954ede28891d",
"title": "Symmetric Difference"
},
{
"id": "aa2e6f85cab2ab736c9a9b24",
"title": "Exact Change"
},
{
"id": "a56138aff60341a09ed6c480",
"title": "Inventory Update"
},
{
"id": "a7bf700cd123b9a54eef01d5",
"title": "No repeats please"
},
{
"id": "a19f0fbe1872186acd434d5a",
"title": "Friendly Date Ranges"
},
{
"id": "bd7158d8c443eddfaeb5bcef",
"title": "Get Set for Basejumps"
},
{
"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"
}
],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
}
]
}

View File

@ -0,0 +1,111 @@
{
"name": "Gear up for Success",
"order": 4,
"time": "10m",
"challenges": [
{
"id": "560add65cb82ac38a17513c2",
"title": "Browse Camper News",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/YNwsMXM.gif",
"A gif showing how you can access our Camper News page and click the \"upvote\" button to upvote a story.",
"Click the \"News\" button in your upper right hand corner. <br>You can browse links on Camper News and upvote the ones that you enjoy.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add65cb82ac38a17513c1",
"title": "Reference our Wiki",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/4GO4zcI.gif",
"A gif showing how you can click the \"Wiki\" button in your upper-right corner to access the wiki.",
"Click the \"Wiki\" button in your upper right hand corner. <br>Our community has contributed lots of useful information to this searchable wiki.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "570add8ccb82ac38a17513c3",
"title": "Join our LinkedIn Alumni Network",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/vJyiXzU.gif",
"A gif showing how you can click the link below and fill in the necessary fields to add your Free Code Camp studies to your LinkedIn profile.",
"LinkedIn recognizes Free Code Camp as a university. You can gain access to our large alumni network by adding Free Code Camp to your LinkedIn profile's education section. <br>Set your graduation date as next year. <br>For \"Degree\", type \"Full Stack Web Development Certification\". <br>For \"Field of study\", type \"Computer Software Engineering\". <br>Then click \"Save Changes\".",
"https://www.linkedin.com/profile/edit-education?school=Free+Code+Camp"
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add8ccb81ac38a17513c4",
"title": "Commit to a Goal and a Nonprofit",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/Og1ifsn.gif",
"A gif showing how you can commit to a goal for your Free Code Camp studies and pledge a monthly donation to a nonprofit to give you external motivation to reach that goal.",
"You can set a goal and pledge to donate to a nonprofit each month until you achieve that goal. <br>This will give you external motivation in your quest to learn to code, as well as an opportunity to help nonprofits right away. <br>Choose your goal, then choose a monthly donation. When you click \"commit\", the nonprofit's donation page will open in a new tab. <br>This is completely optional, and you can change your commitment or stop it at any time.",
"/commit"
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
}
]
}

View File

@ -0,0 +1,275 @@
{
"name": "Get Started with Free Code Camp",
"order": 1,
"time": "10m",
"challenges": [
{
"id": "560add10cb82ac38a17513be",
"title": "Learn how Free Code Camp Works",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/RlEk2IF.jpg",
"A picture of Free Code Camp's 4 benefits: Get connected, Learn JavaScript, Build your Portfolio, Help nonprofits",
"Welcome to Free Code Camp. We're an open source community of busy people who learn to code and help nonprofits.",
""
],
[
"http://i.imgur.com/Elb3dfj.jpg",
"A screenshot of some of our campers coding together in Toronto.",
"<bold>Learning to code is hard.</bold> To succeed, you'll need lots of practice and support. That's why we've created a rigorous curriculum and supportive community.",
""
],
[
"http://i.imgur.com/D7Y5luw.jpg",
"A graph of the rate of job growth against growth in computer science degree graduates. There are 1.4 million jobs and only 400 million people to fill them.",
"There are thousands of coding jobs currently going unfilled, and the demand for coders grows every year.",
""
],
[
"http://i.imgur.com/WD3STY6.jpg",
"Photos of three campers who've gotten jobs after learning to code at Free Code Camp.",
"Free Code Camp is a proven path to your first coding job. In fact, no one has actually completed our entire program, because campers get jobs before they're able to.",
""
],
[
"http://i.imgur.com/dLx8nrg.jpg",
"An illustration showing that you will learn HTML5, CSS3, JavaScript, Databases, Git, Node.js, Angular.js and Agile.",
"During the first half of Free Code Camp, you'll learn technologies like HTML5, Node.js and databases.",
""
],
[
"http://i.imgur.com/syJxavV.jpg",
"A screenshot of our Front End Development Certificate",
"About 400 hours into Free Code Camp, you'll earn your verified Front End Development Certification.",
""
],
[
"http://i.imgur.com/sKYQhdG.jpg",
"A screenshot of our Full Stack Development Certificate",
"About 800 hours into Free Code Camp, you'll earn your verified Full Stack Development Certification.",
""
],
[
"http://i.imgur.com/yXyxbDd.jpg",
"A screen shot of our nonprofit project directory.",
"Then you'll build several real-life projects for nonprofits. By the time you finish, you'll have a portfolio of real apps that people use every day.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add37cb82ac38a17513bf",
"title": "Create a GitHub Account and Join our Chat Rooms",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/EAR7Lvh.jpg",
"A screenshot of our one of our Gitter chat rooms.",
"Now let's join Free Code Camp's chat rooms. You can come here any time of day to hang out, ask questions, or find another camper to pair program with. First you'll need a GitHub account.",
""
],
[
"http://i.imgur.com/FEImaEN.gif",
"A gif showing you to click the link below to go to GitHub. Fill in the necessary fields and click submit.",
"Create an account with GitHub. Be sure to use your real email address - GitHub will keep this private.",
"https://github.com/join"
],
[
"http://i.imgur.com/ALN6zPK.gif",
"A gif showing you how to click the profile image in the upper right hand corner of GitHub. Upload a photo of yourself or you will continue to use the automatically generated pixel art. Then fill in the remaining form fields and click submit.",
"Click the pixel art in the upper right hand corner of GitHub, then choose settings. <br>Upload a picture of yourself. A picture of your face works best. This is how your fellow campers will see you in our chat rooms, so put your best foot forward. <br>You can add your city and your name if you want.",
"https://github.com/settings/profile"
],
[
"http://i.imgur.com/pYk0wOk.gif",
"A gif showing how you can star a GitHub repo.",
"Go to Free Code Camp's open-source repository and \"star\" it. \"Starring\" is the GitHub equivalent of \"liking\" something.",
"https://github.com/freecodecamp/freecodecamp"
],
[
"http://i.imgur.com/zwYPeQT.gif",
"A gif showing you how to click the link below to go to our chat room and click the \"sign in with GitHub\" button. Then you can click into the text input field and type a message to your fellow campers.",
"Now that you have a GitHub account, you can join our main chat room by logging in with GitHub. Introduce yourself by saying \"Hello world!\". <br>Tell your fellow campers how you found Free Code Camp. Also tell us why you want to learn to code.",
"https://gitter.im/FreeCodeCamp/FreeCodeCamp"
],
[
"http://i.imgur.com/Ecs5XAd.gif",
"A gif showing you how you can click the settings button in the upper right hand corner and modify your notification settings.",
"Our chat rooms are extremely active. You should change your settings so you're only notified if someone mentions you.",
""
],
[
"http://i.imgur.com/T0bGJPe.gif",
"A gif showing how you can click on a user profile image to initiate a private message with that user.",
"Please note that all of our chat rooms are visible to the public. If you need to share sensitive information, such as an email address or phone number, do it in a private message.",
""
],
[
"http://i.imgur.com/vDTMJSh.gif",
"A gif showing that you can tab back and forth between challenges and our chat rooms.",
"Keep our chat room open while you work through our challenges. That way, you can ask for help if you get stuck. You can also socialize with other campers when you feel like taking a break.",
""
],
[
"http://i.imgur.com/WvQvNGN.gif",
"A gif showing how you can click the link below to download a native chat room app for your computer.",
"You can also download the chat room app to your computer or phone.",
"https://gitter.im/apps"
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add56cb82ac38a17513c0",
"title": "Configure your Code Portfolio",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/tP2ccTE.gif",
"A gif showing how you can click your profile image in your upper right hand corner to your code portfolio and connect GitHub.",
"Check out your code portfolio. Click your picture in your upper right hand corner. To activate your code portfolio, you'll need to link your GitHub account with Free Code Camp. <br>Your code portfolio shows your progress and how many Brownie Points you have. You can get Brownie Points by completing challenges and by helping other campers in our chat rooms. If you get Brownie Points on several days in a row, you'll get a streak.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add71cb82ac38a17513c2",
"title": "Join a Campsite in Your City",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/NAOFJWN.jpg",
"A picture of some of our campers meeting in a local cafe. 3 men and 3 women are sitting around a table with laptops out, and are smiling and coding.",
"Our Campsites help you code with campers in your city. You can coordinate study groups or attend local coding events together.",
""
],
[
"http://i.imgur.com/fTFMjwf.gif",
"A gif showing how you can click the link below, find your city on the list of Campsites, then click on the Facebook link for your city and join your city's Facebook group.",
"Find your city on this list and click it. This will take you to your city's Campsite's Facebook group. <br>Click the \"Join group\" button to apply to join your city's Facebook group. Someone from the campsite should approve you shortly. <br>If your city isn't on this list, scroll to the bottom of the wiki article for instructions for how you can create your city's Campsite.",
"https://github.com/FreeCodeCamp/freecodecamp/wiki/List-of-Free-Code-Camp-city-based-Campsites"
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "560add8ccb82ac38a17513c4",
"title": "Learn What to Do If You Get Stuck",
"challengeSeed": [],
"description": [
[
"http://i.imgur.com/lzKvwU2.jpg",
"The text \"Coding is hard.\"",
"Coding is hard. You will get stuck. Even experienced coders get stuck. The key is knowing how to get unstuck.",
""
],
[
"http://i.imgur.com/sfsidp6.jpg",
"The text \"It takes time to get good at coding.\"",
"It takes time to get good at coding. You wouldn't expect to beat a chess master after playing for 3 months. Don't expect to build the next Facebook after coding for 3 months.",
""
],
[
"http://i.imgur.com/EoTfOyC.jpg",
"An image of some of our campers coding together in Montreal.",
"Keep practicing coding every day and hanging out with other people who code, and you will becoming a job-ready coder.",
""
],
[
"http://i.imgur.com/EWWZBag.jpg",
"An image with the text \"1. Read the error 2. Search Google 3. Ask for help.",
"Any time you get stuck or don't know what to do next: Read-Search-Ask.",
""
],
[
"http://i.imgur.com/99BfAcK.jpg",
"An image showing jQuery documentation",
"First, read the documentation or error message. A key skill that good coders have is the ability to interpret and then follow instructions.",
""
],
[
"http://i.imgur.com/GxvrsFb.gif",
"A gif showing you how to do an advanced Google search. First, we enter the query \"jquery doesn't run when my page loads\". Then we click search tools button and change the \"Any time\" select box to \"within the last year\". Then we click on a result and read through the article and find our answer.",
"If that didn't help, search Google. Good Google queries take a lot of practice. When you search Google, you usually want to include the language or framework you're using. You also want to limit the results to a recent period.",
""
],
[
"http://i.imgur.com/LZYU7p2.gif",
"A gif showing us following the link below to go to the help chat room and ask \"jquery doesn't run when my page loads\".",
"If that didn't help, ask your friends. If you have trouble, you can ask your fellow campers in our help chat room.",
"https://gitter.im/FreeCodeCamp/Help"
],
[
"http://i.imgur.com/ZRgXraT.gif",
"A gif showing us scrolling through our challenge map.",
"Now you're ready to start coding. <br>The \"Map\" button in your upper right hand corner will show you our challenge map. <br>We recommend that you complete these from top to bottom, at a sustainable pace. <br>Our open source community is constantly improving our challenges, so don't be surprised if they change or move around. Don't worry about going back - just keep moving forward. <br>You can always go to your most recent challenge by clicking the \"Learn\" button.",
""
]
],
"type": "Waypoint",
"challengeType": 7,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
}
]
}

View File

@ -1,21 +1,21 @@
{
"name": "Git",
"order" : 0.016,
"order" : 17,
"time": "3h",
"challenges": [
{
"id": "bd7353d8c341eddeaeb5bd0f",
"title": "Save your Code Revisions Forever with Git",
"difficulty": 0.01,
"challengeSeed": ["133316034"],
"description": [
"We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.",
"If you don't already have Cloud 9 account, create one now at <a href='http://c9.io' target='_blank'>http://c9.io</a>.",
"Open up <a href='http://c9.io' target='_blank'>http://c9.io</a> and sign in to your account.",
"Click on Create New Workspace at the top right of the c9.io page, then click on the \"Create a new workspace\" popup that appears below it the button after you click on it.",
"Give your workspace a name.",
"Click on the \"+\" icon at the top right of the c9.io page to create a new workspace.",
"Give your workspace a name and an optional description.",
"Choose Node.js in the selection area below the name field.",
"Click the Create button. Then click into your new workspace.",
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
"Click the \"Create workspace\" button.",
"Once C9 builds and loads your workspace, you should see a terminal window in the lower right hand corner. In this window use the following commands. You don't need to know what these mean at this point.",
"Install <code>git-it</code> with this command: <code>npm install -g git-it</code>",
"Now start the tutorial by running <code>git-it</code>.",
"Note that you can resize the c9.io's windows by dragging their borders.",

View File

@ -1,11 +1,11 @@
{
"name": "Hikes",
"order": 0.050,
"time": "3h",
"challenges": [
{
"id": "bd7128d8c441eddfbeb5bddf",
"title": "Computer Basics 1: The 4 Basic Parts of a Computer",
"difficulty": 9.01,
"challengeSeed": [
"132542064"
],
@ -45,7 +45,6 @@
{
"id": "bd7127d8c441eddfbeb5bddf",
"title": "Computer Basics 2: More Computer Hardware",
"difficulty": 9.02,
"challengeSeed": [
"132542458"
],
@ -84,7 +83,6 @@
{
"id": "bd7126d8c441eddfbeb5bddf",
"title": "Computer Basics 3: Intro to Binary Code",
"difficulty": 9.03,
"challengeSeed": [
"132542757"
],
@ -118,7 +116,6 @@
{
"id": "bd7125d8c441eddfbeb5bddf",
"title": "Computer Basics 4: Decoding a Binary Number",
"difficulty": 9.04,
"challengeSeed": [
"132543332"
],
@ -154,7 +151,6 @@
{
"id": "bd7124d8c441eddfbeb5bddf",
"title": "Computer Basics 5: How To Measure Data Size",
"difficulty": 9.05,
"challengeSeed": [
"132543959"
],
@ -193,7 +189,6 @@
{
"id": "bd7123d8c441eddfbeb5bddf",
"title": "Computer Basics 6: Measuring Data Speed",
"difficulty": 9.06,
"challengeSeed": [
"132545171"
],
@ -230,7 +225,6 @@
{
"id": "bd7122d8c441eddfbeb5bddf",
"title": "Computer Basics 7: Binary Bytes",
"difficulty": 9.07,
"challengeSeed": [
"132545417"
],
@ -264,7 +258,6 @@
{
"id": "bd7121d8c441eddfbeb5bddf",
"title": "Computer Basics 8: Types of Computers",
"difficulty": 9.08,
"challengeSeed": [
"132546182"
],
@ -303,7 +296,6 @@
{
"id": "bd7120d8c441eddfbeb5bddf",
"title": "Computer Basics 9: More on the Motherboard",
"difficulty": 9.09,
"challengeSeed": [
"132547285"
],
@ -344,7 +336,6 @@
{
"id": "bd712fd8c441eddfbeb5bddf",
"title": "Computer Basics 10: Data Networks",
"difficulty": 9.10,
"challengeSeed": [
"132547590"
],
@ -384,7 +375,6 @@
{
"id": "bd712ed8c441eddfbeb5bddf",
"title": "Computer Basics 11: IP Addresses",
"difficulty": 9.11,
"challengeSeed": [
"132548071"
],
@ -423,7 +413,6 @@
{
"id": "bd712dd8c441eddfbeb5bddf",
"title": "Computer Basics 12: How the Internet Works",
"difficulty": 9.12,
"challengeSeed": [
"132548579"
],
@ -462,7 +451,6 @@
{
"id": "bd712cd8c441eddfbeb5bddf",
"title": "Computer Basics 13: Software",
"difficulty": 9.13,
"challengeSeed": [
"132548908"
],
@ -495,7 +483,6 @@
{
"id": "bd712bd8c441eddfbeb5bddf",
"title": "What Do Programmers Do?",
"difficulty": 9.14,
"challengeSeed": [
"133166912"
],
@ -532,7 +519,6 @@
{
"id": "bd712ad8c441eddfbeb5bddf",
"title": "Console and Logging",
"difficulty": 9.15,
"challengeSeed": [
"133170880"
],
@ -569,7 +555,6 @@
{
"id": "bd7119d8c441eddfbeb5bddf",
"title": "Variables In Code",
"difficulty": 9.16,
"challengeSeed": [
"133172920"
],
@ -602,7 +587,6 @@
{
"id": "bd7029d8c441eddfbeb5bddf",
"title": "Source Code",
"difficulty": 9.17,
"challengeSeed": [
"133177129"
],
@ -647,7 +631,6 @@
{
"id": "bd7129d8b441eddfbeb5bddf",
"title": "Routers and Packets",
"difficulty": 9.18,
"challengeSeed": [
"133181251"
],
@ -698,7 +681,6 @@
{
"id": "bd7129d8a441eddfbeb5bddf",
"title": "Hardware: Chips and Moore's Law",
"difficulty": 9.19,
"challengeSeed": [
"133182057"
],
@ -735,7 +717,6 @@
{
"id": "bd7129d80441eddfbeb5bddf",
"title": "Analog vs Digital and File Compression",
"difficulty": 9.20,
"challengeSeed": [
"133182587"
],
@ -774,7 +755,6 @@
{
"id": "bd7129d89441eddfbeb5bddf",
"title": "Computer Security",
"difficulty": 9.21,
"challengeSeed": [
"133186284"
],

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
{
"name": "Intermediate Algorithm Scripting",
"order": 0.009,
"order": 10,
"time": "50h",
"challenges": [
{
"id": "a3566b1109230028080c9345",
"title": "Sum All Numbers in a Range",
"difficulty": "2.00",
"description": [
"We'll pass you an array of two numbers. Return the sum of those two numbers and all numbers between them.",
"The lowest number will not always come first.",
@ -19,17 +19,20 @@
"sumAll([1, 4]);"
],
"tests": [
"expect(sumAll([1, 4])).to.be.a('Number');",
"expect(sumAll([1, 4])).to.equal(10);",
"expect(sumAll([4, 1])).to.equal(10);",
"expect(sumAll([5, 10])).to.equal(45);",
"expect(sumAll([10, 5])).to.equal(45);"
"assert(typeof(sumAll([1, 4])) === \"number\", 'message: <code>sumAll()</code> should return a number.');",
"assert.deepEqual(sumAll([1, 4]), 10, 'message: <code>sumAll([1, 4])</code> should return 10.');",
"assert.deepEqual(sumAll([4, 1]), 10, 'message: <code>sumAll([4, 1])</code> should return 10.');",
"assert.deepEqual(sumAll([5, 10]), 45, 'message: <code>sumAll([5, 10])</code> should return 45.');",
"assert.deepEqual(sumAll([10, 5]), 45, 'message: <code>sumAll([10, 5])</code> should return 45.');"
],
"MDNlinks": [
"Math.max()",
"Math.min()",
"Array.reduce()"
],
"solutions": [
"function sumAll(arr) {\n var sum = 0;\n arr.sort(function(a,b) {return a-b;});\n for (var i = arr[0]; i <= arr[1]; i++) {\n sum += i; \n }\n return sum;\n}\n\nsumAll([1, 4]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -46,7 +49,6 @@
{
"id": "a5de63ebea8dbee56860f4f2",
"title": "Diff Two Arrays",
"difficulty": "2.01",
"description": [
"Compare two arrays and return a new array with any items not found in both of the original arrays.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -61,13 +63,14 @@
"diff([1, 2, 3, 5], [1, 2, 3, 4, 5]);"
],
"tests": [
"expect(diff([1, 2, 3, 5], [1, 2, 3, 4, 5])).to.be.a('array');",
"assert.deepEqual(diff(['diorite', 'andesite', 'grass', 'dirt', 'pink wool', 'dead shrub'], ['diorite', 'andesite', 'grass', 'dirt', 'dead shrub']), ['pink wool'], 'arrays with only one difference');",
"assert.includeMembers(diff(['andesite', 'grass', 'dirt', 'pink wool', 'dead shrub'], ['diorite', 'andesite', 'grass', 'dirt', 'dead shrub']), ['diorite', 'pink wool'], 'arrays with more than one difference');",
"assert.deepEqual(diff(['andesite', 'grass', 'dirt', 'dead shrub'], ['andesite', 'grass', 'dirt', 'dead shrub']), [], 'arrays with no difference');",
"assert.deepEqual(diff([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], 'arrays with numbers');",
"assert.includeMembers(diff([1, 'calf', 3, 'piglet'], [1, 'calf', 3, 4]), ['piglet', 4], 'arrays with numbers and strings');",
"assert.deepEqual(diff([], ['snuffleupagus', 'cookie monster', 'elmo']), ['snuffleupagus', 'cookie monster', 'elmo'], 'empty array');"
"assert(typeof(diff([1, 2, 3, 5], [1, 2, 3, 4, 5])) === \"object\", 'message: <code>diff()</code> should return an array.');",
"assert.deepEqual(diff([\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"pink wool\"], 'message: <code>[\"diorite\", \"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]</code> should return <code>[\"pink wool\"]</code>.');",
"assert.includeMembers(diff([\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [\"diorite\", \"pink wool\"], 'message: <code>[\"andesite\", \"grass\", \"dirt\", \"pink wool\", \"dead shrub\"], [\"diorite\", \"andesite\", \"grass\", \"dirt\", \"dead shrub\"]</code> should return <code>[\"diorite\", \"pink wool\"]</code>.');",
"assert.deepEqual(diff([\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]), [], 'message: <code>[\"andesite\", \"grass\", \"dirt\", \"dead shrub\"], [\"andesite\", \"grass\", \"dirt\", \"dead shrub\"]</code> should return <code>[]</code>.');",
"assert.deepEqual(diff([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4], 'message: <code>[1, 2, 3, 5], [1, 2, 3, 4, 5]</code> should return <code>[4]</code>.');",
"assert.includeMembers(diff([1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]), [\"piglet\", 4], 'message: <code>[1, \"calf\", 3, \"piglet\"], [1, \"calf\", 3, 4]</code> should return <code>[\"piglet\", 4]</code>.');",
"assert.deepEqual(diff([], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]), [\"snuffleupagus\", \"cookie monster\", \"elmo\"], 'message: <code>[], [\"snuffleupagus\", \"cookie monster\", \"elmo\"]</code> should return <code>[\"snuffleupagus\", \"cookie monster\", \"elmo\"]</code>.');",
"assert.includeMembers(diff([1, \"calf\", 3, \"piglet\"], [7, \"filly\"]), [1, \"calf\", 3, \"piglet\", 7, \"filly\"], 'message: <code>[1, \"calf\", 3, \"piglet\"], [7, \"filly\"]</code> should return <code>[1, \"calf\", 3, \"piglet\", 7, \"filly\"]</code>.');"
],
"MDNlinks": [
"Comparison Operators",
@ -76,6 +79,9 @@
"Array.indexOf()",
"Array.concat()"
],
"solutions": [
"function diff(arr1, arr2) {\n var newArr = [];\n var h1 = Object.create(null);\n arr1.forEach(function(e) {\n h1[e] = e;\n });\n \n var h2 = Object.create(null);\n arr2.forEach(function(e) {\n h2[e] = e;\n });\n \n Object.keys(h1).forEach(function(e) {\n if (!(e in h2)) newArr.push(h1[e]);\n });\n Object.keys(h2).forEach(function(e) {\n if (!(e in h1)) newArr.push(h2[e]);\n });\n // Same, same; but different.\n return newArr;\n}\n\ndiff([1, 2, 3, 5], [1, 2, 3, 4, 5]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -93,13 +99,26 @@
"id": "a7f4d8f2483413a6ce226cac",
"title": "Roman Numeral Converter",
"tests": [
"expect(convert(12)).to.equal(\"XII\");",
"expect(convert(5)).to.equal(\"V\");",
"expect(convert(9)).to.equal(\"IX\");",
"expect(convert(29)).to.equal(\"XXIX\");",
"expect(convert(16)).to.equal(\"XVI\");"
"assert.deepEqual(convert(5), \"V\", 'message: <code>convert(5)</code> should return \"V\".');",
"assert.deepEqual(convert(9), \"IX\", 'message: <code>convert(9)</code> should return \"IX\".');",
"assert.deepEqual(convert(12), \"XII\", 'message: <code>convert(12)</code> should return \"XII\".');",
"assert.deepEqual(convert(16), \"XVI\", 'message: <code>convert(16)</code> should return \"XVI\".');",
"assert.deepEqual(convert(29), \"XXIX\", 'message: <code>convert(29)</code> should return \"XXIX\".');",
"assert.deepEqual(convert(44), \"XLIV\", 'message: <code>convert(44)</code> should return \"XLIV\".');",
"assert.deepEqual(convert(45), \"XLV\", '<code>convert(45)</code> should return \"XLV\"');",
"assert.deepEqual(convert(68), \"LXVIII\", '<code>convert(68)</code> should return \"LXVIII\"');",
"assert.deepEqual(convert(83), \"LXXXIII\", '<code>convert(83)</code> should return \"LXXXIII\"');",
"assert.deepEqual(convert(97), \"XCVII\", '<code>convert(97)</code> should return \"XCVII\"');",
"assert.deepEqual(convert(99), \"XCIX\", '<code>convert(99)</code> should return \"XCIX\"');",
"assert.deepEqual(convert(500), \"D\", '<code>convert(500)</code> should return \"D\"');",
"assert.deepEqual(convert(501), \"DI\", '<code>convert(501)</code> should return \"DI\"');",
"assert.deepEqual(convert(649), \"DCXLIX\", '<code>convert(649)</code> should return \"DCXLIX\"');",
"assert.deepEqual(convert(798), \"DCCXCVIII\", '<code>convert(798)</code> should return \"DCCXCVIII\"');",
"assert.deepEqual(convert(891), \"DCCCXCI\", '<code>convert(891)</code> should return \"DCCCXCI\"');",
"assert.deepEqual(convert(1000), \"M\", '<code>convert(1000)</code> should return \"M\"');",
"assert.deepEqual(convert(1004), \"MIV\", '<code>convert(1004)</code> should return \"MIV\"');",
"assert.deepEqual(convert(1006), \"MVI\", '<code>convert(1006)</code> should return \"MVI\"');"
],
"difficulty": "2.02",
"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.",
@ -113,10 +132,57 @@
"convert(36);"
],
"MDNlinks": [
"Roman Numerals",
"Array.splice()",
"Array.indexOf()",
"Array.join()"
],
"solutions": [
"function convert(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}\n\nconvert(36);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "a8e512fbe388ac2f9198f0fa",
"title": "Where art thou",
"description": [
"Make a function that looks through an array of objects (first argument) and returns an array of all objects that have matching property and value pairs (second argument). Each property and value pair of the source object has to be present in the object from the collection if it is to be included in the returned array.",
"For example, if the first argument is <code>[{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }]</code>, and the second argument is <code>{ last: \"Capulet\" }</code>, then you must return the third object from the array (the first argument), because it contains the property and it's value, that was passed on as the second argument.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Write your own code."
],
"challengeSeed": [
"function where(collection, source) {",
" var arr = [];",
" // What's in a name?",
" return arr;",
"}",
"",
"where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" });"
],
"tests": [
"assert.deepEqual(where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" }), [{ first: \"Tybalt\", last: \"Capulet\" }], 'message: <code>where([{ first: \"Romeo\", last: \"Montague\" }, { first: \"Mercutio\", last: null }, { first: \"Tybalt\", last: \"Capulet\" }], { last: \"Capulet\" })</code> should return <code>[{ first: \"Tybalt\", last: \"Capulet\" }]</code>.');",
"assert.deepEqual(where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 }), [{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], 'message: <code>where([{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }], { \"a\": 1 })</code> should return <code>[{ \"a\": 1 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2 }]</code>.');",
"assert.deepEqual(where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 }), [{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], 'message: <code>where([{ \"a\": 1, \"b\": 2 }, { \"a\": 1 }, { \"a\": 1, \"b\": 2, \"c\": 2 }], { \"a\": 1, \"b\": 2 })</code> should return <code>[{ \"a\": 1, \"b\": 2 }, { \"a\": 1, \"b\": 2, \"c\": 2 }]</code>.');"
],
"MDNlinks": [
"Global Object",
"Object.hasOwnProperty()",
"Object.keys()"
],
"solutions": [
"function where(collection, source) {\n var arr = [];\n var keys = Object.keys(source);\n collection.forEach(function(e) {\n if(keys.every(function(key) {return e[key] === source[key];})) {\n arr.push(e); \n }\n });\n return arr;\n}\n\nwhere([{ first: 'Romeo', last: 'Montague' }, { first: 'Mercutio', last: null }, { first: 'Tybalt', last: 'Capulet' }], { last: 'Capulet' });\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -134,33 +200,35 @@
"id": "a0b5010f579e69b815e7c5d6",
"title": "Search and Replace",
"tests": [
"expect(replace(\"Let us go to the store\", \"store\", \"mall\")).to.equal(\"Let us go to the mall\");",
"expect(replace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\")).to.equal(\"He is Sitting on the couch\");",
"expect(replace(\"This has a spellngi error\", \"spellngi\", \"spelling\")).to.equal(\"This has a spelling error\");",
"expect(replace(\"His name is Tom\", \"Tom\", \"john\")).to.equal(\"His name is John\");",
"expect(replace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\")).to.equal(\"Let us get back to more Bonfires\");"
"assert.deepEqual(myReplace(\"Let us go to the store\", \"store\", \"mall\"), \"Let us go to the mall\", 'message: <code>myReplace(\"Let us go to the store\", \"store\", \"mall\")</code> should return \"Let us go to the mall\".');",
"assert.deepEqual(myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\"), \"He is Sitting on the couch\", 'message: <code>myReplace(\"He is Sleeping on the couch\", \"Sleeping\", \"sitting\")</code> should return \"He is Sitting on the couch\".');",
"assert.deepEqual(myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\"), \"This has a spelling error\", 'message: <code>myReplace(\"This has a spellngi error\", \"spellngi\", \"spelling\")</code> should return \"This has a spelling error\".');",
"assert.deepEqual(myReplace(\"His name is Tom\", \"Tom\", \"john\"), \"His name is John\", 'message: <code>myReplace(\"His name is Tom\", \"Tom\", \"john\")</code> should return \"His name is John\".');",
"assert.deepEqual(myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\"), \"Let us get back to more Bonfires\", 'message: <code>myReplace(\"Let us get back to more Coding\", \"Coding\", \"bonfires\")</code> should return \"Let us get back to more Bonfires\".');"
],
"difficulty": "2.03",
"description": [
"Perform a search and replace on the sentence using the arguments provided and return the new sentence.",
"First argument is the sentence to perform the search and replace on.",
"Second argument is the word that you will be replacing (before).",
"Third argument is what you will be replacing the second argument with (after).",
"NOTE: Preserve the case of the original word when you are replacing it. For example if you mean to replace the word 'Book' with the word 'dog', it should be replaced as 'Dog'",
"NOTE: Preserve the case of the original word when you are replacing it. For example if you mean to replace the word \"Book\" with the word \"dog\", it should be replaced as \"Dog\"",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function replace(str, before, after) {",
"function myReplace(str, before, after) {",
" return str;",
"}",
"",
"replace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");"
"myReplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");"
],
"MDNlinks": [
"Array.splice()",
"String.replace()",
"Array.join()"
],
"solutions": [
"function replace(str, before, after) {\n if (before.charAt(0) === before.charAt(0).toUpperCase()) {\n after = after.charAt(0).toUpperCase() + after.substring(1);\n } else {\n after = after.charAt(0).toLowerCase() + after.substring(1);\n }\n return str.replace(before, after);\n}\n\nreplace(\"A quick brown fox jumped over the lazy dog\", \"jumped\", \"leaped\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -178,13 +246,12 @@
"id": "aa7697ea2477d1316795783b",
"title": "Pig Latin",
"tests": [
"expect(translate(\"california\")).to.equal(\"aliforniacay\");",
"expect(translate(\"paragraphs\")).to.equal(\"aragraphspay\");",
"expect(translate(\"glove\")).to.equal(\"oveglay\");",
"expect(translate(\"algorithm\")).to.equal(\"algorithmway\");",
"expect(translate(\"eight\")).to.equal(\"eightway\");"
"assert.deepEqual(translate(\"california\"), \"aliforniacay\", 'message: <code>translate(\"california\")</code> should return \"aliforniacay\".');",
"assert.deepEqual(translate(\"paragraphs\"), \"aragraphspay\", 'message: <code>translate(\"paragraphs\")</code> should return \"aragraphspay\".');",
"assert.deepEqual(translate(\"glove\"), \"oveglay\", 'message: <code>translate(\"glove\")</code> should return \"oveglay\".');",
"assert.deepEqual(translate(\"algorithm\"), \"algorithmway\", 'message: <code>translate(\"algorithm\")</code> should return \"algorithmway\".');",
"assert.deepEqual(translate(\"eight\"), \"eightway\", 'message: <code>translate(\"eight\")</code> should return \"eightway\".');"
],
"difficulty": "2.04",
"description": [
"Translate the provided string to pig latin.",
"<a href=\"http://en.wikipedia.org/wiki/Pig_Latin\" target=\"_blank\">Pig Latin</a> takes the first consonant (or consonant cluster) of an English word, moves it to the end of the word and suffixes an \"ay\".",
@ -205,6 +272,9 @@
"String.substr()",
"String.split()"
],
"solutions": [
"function translate(str) {\n if (isVowel(str.charAt(0))) return str + \"way\";\n var front = [];\n str = str.split('');\n while (str.length && !isVowel(str[0])) {\n front.push(str.shift());\n }\n return [].concat(str, front).join('') + 'ay';\n}\n\nfunction isVowel(c) {\n return ['a', 'e', 'i', 'o', 'u'].indexOf(c.toLowerCase()) !== -1;\n}\n\ntranslate(\"consonant\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -222,17 +292,16 @@
"id": "afd15382cdfb22c9efe8b7de",
"title": "DNA Pairing",
"tests": [
"assert.deepEqual(pair(\"ATCGA\"),[['A','T'],['T','A'],['C','G'],['G','C'],['A','T']], 'should return the dna pair');",
"assert.deepEqual(pair(\"TTGAG\"),[['T','A'],['T','A'],['G','C'],['A','T'],['G','C']], 'should return the dna pair');",
"assert.deepEqual(pair(\"CTCTA\"),[['C','G'],['T','A'],['C','G'],['T','A'],['A','T']], 'should return the dna pair');"
"assert.deepEqual(pair(\"ATCGA\"),[[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]], 'message: <code>pair(\"ATCGA\")</code> should return <code>[[\"A\",\"T\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"G\",\"C\"],[\"A\",\"T\"]]</code>.');",
"assert.deepEqual(pair(\"TTGAG\"),[[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]], 'message: <code>pair(\"TTGAG\")</code> should return <code>[[\"T\",\"A\"],[\"T\",\"A\"],[\"G\",\"C\"],[\"A\",\"T\"],[\"G\",\"C\"]]</code>.');",
"assert.deepEqual(pair(\"CTCTA\"),[[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]], 'message: <code>pair(\"CTCTA\")</code> should return <code>[[\"C\",\"G\"],[\"T\",\"A\"],[\"C\",\"G\"],[\"T\",\"A\"],[\"A\",\"T\"]]</code>.');"
],
"difficulty": "2.05",
"description": [
"The DNA strand is missing the pairing element. Take each character, get its pair, and return the results as a 2d array.",
"<a href=\"http://en.wikipedia.org/wiki/Base_pair\" target=\"_blank\">Base pairs</a> are a pair of AT and CG. Match the missing element to the provided character.",
"Return the provided character as the first element in each array.",
"For example, for the input GCG, return [['G', 'C'], ['C','G'],['G', 'C']]",
"The charater and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array.",
"For example, for the input GCG, return [[\"G\", \"C\"], [\"C\",\"G\"],[\"G\", \"C\"]]",
"The character and its pair are paired up in an array, and all the arrays are grouped into one encapsulating array.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
@ -246,6 +315,9 @@
"Array.push()",
"String.split()"
],
"solutions": [
"var lookup = Object.create(null);\nlookup.A = 'T';\nlookup.T = 'A';\nlookup.C = 'G';\nlookup.G = 'C';\n\nfunction pair(str) {\n return str.split('').map(function(p) {return [p, lookup[p]];});\n}\n\npair(\"GCG\");\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -262,7 +334,6 @@
{
"id": "af7588ade1100bde429baf20",
"title": "Missing letters",
"difficulty": "2.05",
"description": [
"Find the missing letter in the passed letter range and return it.",
"If all letters are present in the range, return undefined.",
@ -273,18 +344,21 @@
" return str;",
"}",
"",
"fearNotLetter('abce');"
"fearNotLetter(\"abce\");"
],
"tests": [
"expect(fearNotLetter('abce')).to.equal('d');",
"expect(fearNotLetter('bcd')).to.be.undefined;",
"expect(fearNotLetter('abcdefghjklmno')).to.equal('i');",
"expect(fearNotLetter('yz')).to.be.undefined;"
"assert.deepEqual(fearNotLetter(\"abce\"), \"d\", 'message: <code>fearNotLetter(\"abce\")</code> should return \"d\".');",
"assert.deepEqual(fearNotLetter(\"abcdefghjklmno\"), \"i\", 'message: <code>fearNotLetter(\"abcdefghjklmno\")</code> should return \"i\".');",
"assert.isUndefined(fearNotLetter(\"bcd\"), 'message: <code>fearNotLetter(\"bcd\")</code> should return undefined.');",
"assert.isUndefined(fearNotLetter(\"yz\"), 'message: <code>fearNotLetter(\"yz\")</code> should return undefined.');"
],
"MDNlinks": [
"String.charCodeAt()",
"String.fromCharCode()"
],
"solutions": [
"function fearNotLetter(str) {\n var s = str.split('').map(function(c) {return c.charCodeAt(0);});\n for (var i = 1; i < s.length; i++) {\n if (s[i]-1 != s[i-1]) {\n return String.fromCharCode(s[i]-1);\n }\n }\n}\n\nfearNotLetter('abce');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -301,7 +375,6 @@
{
"id": "a77dbc43c33f39daa4429b4f",
"title": "Boo who",
"difficulty": "2.06",
"description": [
"Check if a value is classified as a boolean primitive. Return true or false.",
"Boolean primitives are true and false.",
@ -316,18 +389,21 @@
"boo(null);"
],
"tests": [
"assert.strictEqual(boo(true), true);",
"assert.strictEqual(boo(false), true);",
"assert.strictEqual(boo([1, 2, 3]), false);",
"assert.strictEqual(boo([].slice), false);",
"assert.strictEqual(boo({ 'a': 1 }), false);",
"assert.strictEqual(boo(1), false);",
"assert.strictEqual(boo(NaN), false);",
"assert.strictEqual(boo('a'), false);"
"assert.strictEqual(boo(true), true, 'message: <code>boo(true)</code> should return true.');",
"assert.strictEqual(boo(false), true, 'message: <code>boo(false)</code> should return true.');",
"assert.strictEqual(boo([1, 2, 3]), false, 'message: <code>boo([1, 2, 3])</code> should return false.');",
"assert.strictEqual(boo([].slice), false, 'message: <code>boo([].slice)</code> should return false.');",
"assert.strictEqual(boo({ \"a\": 1 }), false, 'message: <code>boo({ \"a\": 1 })</code> should return false.');",
"assert.strictEqual(boo(1), false, 'message: <code>boo(1)</code> should return false.');",
"assert.strictEqual(boo(NaN), false, 'message: <code>boo(NaN)</code> should return false.');",
"assert.strictEqual(boo(\"a\"), false, 'message: <code>boo(\"a\")</code> should return false.');"
],
"MDNlinks": [
"Boolean Objects"
],
"solutions": [
"function boo(bool) {\n // What is the new fad diet for ghost developers? The Boolean.\n return typeof(bool) === \"boolean\";\n}\n\nboo(null);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -344,7 +420,6 @@
{
"id": "a105e963526e7de52b219be9",
"title": "Sorted Union",
"difficulty": "2.07",
"description": [
"Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays.",
"In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array.",
@ -360,15 +435,18 @@
"unite([1, 3, 2], [5, 2, 1, 4], [2, 1]);"
],
"tests": [
"assert.deepEqual(unite([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'should return the union of the given arrays');",
"assert.deepEqual(unite([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'should not flatten nested arrays');",
"assert.deepEqual(unite([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5], 'should correctly handle exactly two arguments');",
"assert.deepEqual(unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [ 1, 2, 3, 5, 4, 6, 7, 8 ], 'should correctly handle higher numbers of arguments');"
"assert.deepEqual(unite([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4], 'message: <code>unite([1, 3, 2], [5, 2, 1, 4], [2, 1])</code> should return <code>[1, 3, 2, 5, 4]</code>.');",
"assert.deepEqual(unite([1, 3, 2], [1, [5]], [2, [4]]), [1, 3, 2, [5], [4]], 'message: <code>unite([1, 3, 2], [1, [5]], [2, [4]])</code> should return <code>[1, 3, 2, [5], [4]]</code>.');",
"assert.deepEqual(unite([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5], 'message: <code>unite([1, 2, 3], [5, 2, 1])</code> should return <code>[1, 2, 3, 5]</code>.');",
"assert.deepEqual(unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [1, 2, 3, 5, 4, 6, 7, 8], 'message: <code>unite([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8])</code> should return <code>[1, 2, 3, 5, 4, 6, 7, 8]</code>.');"
],
"MDNlinks": [
"Arguments object",
"Array.reduce()"
],
"solutions": [
"function unite(arr1, arr2, arr3) {\n return [].slice.call(arguments).reduce(function(a, b) {\n return [].concat(a, b.filter(function(e) {return a.indexOf(e) === -1;}));\n }, []);\n}\n\nunite([1, 2, 3], [5, 2, 1, 4], [2, 1]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -385,7 +463,6 @@
{
"id": "a6b0bb188d873cb2c8729495",
"title": "Convert HTML Entities",
"difficulty": "2.07",
"description": [
"Convert the characters \"&\", \"<\", \">\", '\"' (double quote), and \"'\" (apostrophe), in a string to their corresponding HTML entities.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -396,21 +473,24 @@
" return str;",
"}",
"",
"convert('Dolce & Gabbana');"
"convert(\"Dolce & Gabbana\");"
],
"tests": [
"assert.match(convert('Dolce & Gabbana'), /Dolce &(amp|AMP|#x00026|#38); Gabbana/, 'should escape characters');",
"assert.match(convert('Hamburgers < Pizza < Tacos'), /Hamburgers &(lt|LT|#x0003C|#60); Pizza &(lt|LT|#x0003C|#60); Tacos/, 'should escape characters');",
"assert.match(convert('Sixty > twelve'), /Sixty &(gt|GT|#x0003E|#62); twelve/, 'should escape characters');",
"assert.match(convert('Stuff in \"quotation marks\"'), /Stuff in &(quot|QUOT|#x00022|#34);quotation marks&(quot|QUOT|#x00022|#34);/, 'should escape characters');",
"assert.match(convert(\"Shindler's List\"), /Shindler&(apos|#x00027|#39);s List/, 'should escape characters');",
"assert.match(convert('<>'), /&(lt|LT|#x0003C|#60);&(gt|GT|#x0003E|#62);/, 'should escape characters');",
"assert.strictEqual(convert('abc'), 'abc', 'should handle strings with nothing to escape');"
"assert.match(convert(\"Dolce & Gabbana\"), /Dolce &amp; Gabbana/, 'message: <code>convert(\"Dolce & Gabbana\")</code> should return <code>Dolce &&#8203;amp; Gabbana</code>.');",
"assert.match(convert(\"Hamburgers < Pizza < Tacos\"), /Hamburgers &lt; Pizza &lt; Tacos/, 'message: <code>convert(\"Hamburgers < Pizza < Tacos\")</code> should return <code>Hamburgers &&#8203;lt; Pizza &&#8203;lt; Tacos</code>.');",
"assert.match(convert(\"Sixty > twelve\"), /Sixty &gt; twelve/, 'message: <code>convert(\"Sixty > twelve\")</code> should return <code>Sixty &&#8203;gt; twelve</code>.');",
"assert.match(convert('Stuff in \"quotation marks\"'), /Stuff in &quot;quotation marks&quot;/, 'message: <code>convert(&apos;Stuff in \"quotation marks\"&apos;)</code> should return <code>Stuff in &&#8203;quot;quotation marks&&#8203;quot;</code>.');",
"assert.match(convert(\"Shindler's List\"), /Shindler&apos;s List/, 'message: <code>convert(\"Shindler&apos;s List\")</code> should return <code>Shindler&&#8203;apos;s List</code>.');",
"assert.match(convert('<>'), /&lt;&gt;/, 'message: <code>convert(\"<>\")</code> should return <code>&&#8203;lt;&&#8203;gt;</code>.');",
"assert.strictEqual(convert('abc'), 'abc', 'message: <code>convert(\"abc\")</code> should return <code>abc</code>.');"
],
"MDNlinks": [
"RegExp",
"HTML Entities"
],
"solutions": [
"var MAP = { '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&apos;'};\n\nfunction convert(str) {\n return str.replace(/[&<>\"']/g, function(c) {\n return MAP[c];\n });\n}\n\nconvert('Dolce & Gabbana');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -427,7 +507,6 @@
{
"id": "a103376db3ba46b2d50db289",
"title": "Spinal Tap Case",
"difficulty": "2.08",
"description": [
"Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -442,15 +521,18 @@
"spinalCase('This Is Spinal Tap');"
],
"tests": [
"assert.strictEqual(spinalCase('This Is Spinal Tap'), 'this-is-spinal-tap', 'should return spinal case from string with spaces');",
"assert.strictEqual(spinalCase('thisIsSpinalTap'), 'this-is-spinal-tap', 'should return spinal case from string with camel case');",
"assert.strictEqual(spinalCase('The_Andy_Griffith_Show'), 'the-andy-griffith-show', 'should return spinal case from string with snake case');",
"assert.strictEqual(spinalCase('Teletubbies say Eh-oh'), 'teletubbies-say-eh-oh', 'should return spinal case from string with spaces and hyphens');"
"assert.deepEqual(spinalCase(\"This Is Spinal Tap\"), \"this-is-spinal-tap\", 'message: <code>spinalCase(\"This Is Spinal Tap\")</code> should return <code>\"this-is-spinal-tap\"</code>.');",
"assert.strictEqual(spinalCase('thisIsSpinalTap'), \"this-is-spinal-tap\", 'message: <code>spinalCase(\"thisIsSpinalTap\")</code> should return <code>\"this-is-spinal-tap\"</code>.');",
"assert.strictEqual(spinalCase(\"The_Andy_Griffith_Show\"), \"the-andy-griffith-show\", 'message: <code>spinalCase(\"The_Andy_Griffith_Show\")</code> should return <code>\"the-andy-griffith-show\"</code>.');",
"assert.strictEqual(spinalCase(\"Teletubbies say Eh-oh\"), \"teletubbies-say-eh-oh\", 'message: <code>spinalCase(\"Teletubbies say Eh-oh\")</code> should return <code>\"teletubbies-say-eh-oh\"</code>.');"
],
"MDNlinks": [
"RegExp",
"String.replace()"
],
"solutions": [
"function spinalCase(str) {\n // \"It's such a fine line between stupid, and clever.\"\n // --David St. Hubbins\n str = str.replace(/([a-z](?=[A-Z]))/g, '$1 ');\n return str.toLowerCase().replace(/\\ |\\_/g, '-');\n}\n\nspinalCase('This Is Spinal Tap');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -467,7 +549,6 @@
{
"id": "a5229172f011153519423690",
"title": "Sum All Odd Fibonacci Numbers",
"difficulty": "2.09",
"description": [
"Return the sum of all odd Fibonacci numbers up to and including the passed number if it is a Fibonacci number.",
"The first few numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8, and each subsequent number is the sum of the previous two numbers.",
@ -482,16 +563,19 @@
"sumFibs(4);"
],
"tests": [
"expect(sumFibs(1)).to.be.a('number');",
"expect(sumFibs(1000)).to.equal(1785);",
"expect(sumFibs(4000000)).to.equal(4613732);",
"expect(sumFibs(4)).to.equal(5);",
"expect(sumFibs(75024)).to.equal(60696);",
"expect(sumFibs(75025)).to.equal(135721);"
"assert(typeof(sumFibs(1)) === \"number\", 'message: <code>sumFibs(1)</code> should return a number.');",
"assert.deepEqual(sumFibs(1000), 1785, 'message: <code>sumFibs(1000)</code> should return 1785.');",
"assert.deepEqual(sumFibs(4000000), 4613732, 'message: <code>sumFibs(4000000)</code> should return 4613732.');",
"assert.deepEqual(sumFibs(4), 5, 'message: <code>sumFibs(4)</code> should return 5.');",
"assert.deepEqual(sumFibs(75024), 60696, 'message: <code>sumFibs(75024)</code> should return 60696.');",
"assert.deepEqual(sumFibs(75025), 135721, 'message: <code>sumFibs(75025)</code> should return 135721.');"
],
"MDNlinks": [
"Remainder"
],
"solutions": [
"function sumFibs(num) {\n var a = 1; \n var b = 1;\n var s = 0;\n while (a <= num) {\n if (a % 2 !== 0) { \n s += a; \n }\n a = [b, b=b+a][0];\n }\n return s;\n}\n\nsumFibs(4);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -508,7 +592,6 @@
{
"id": "a3bfc1673c0526e06d3ac698",
"title": "Sum All Primes",
"difficulty": "2.10",
"description": [
"Sum all the prime numbers up to and including the provided number.",
"A prime number is defined as having only two divisors, 1 and itself. For example, 2 is a prime number because it's only divisible by 1 and 2. 1 isn't a prime number, because it's only divisible by itself.",
@ -523,14 +606,17 @@
"sumPrimes(10);"
],
"tests": [
"expect(sumPrimes(10)).to.be.a('number');",
"expect(sumPrimes(10)).to.equal(17);",
"expect(sumPrimes(977)).to.equal(73156);"
"assert.deepEqual(typeof(sumPrimes(10)), \"number\", 'message: <code>sumPrimes()</code> should return a number.');",
"assert.deepEqual(sumPrimes(10), 17, 'message: <code>sumPrimes(10)</code> should return 17.');",
"assert.deepEqual(sumPrimes(977), 73156, 'message: <code>sumPrimes(977)</code> should return 73156.');"
],
"MDNlinks": [
"For Loops",
"Array.push()"
],
"solutions": [
"function eratosthenesArray(n) {\n var primes = [];\n if (n > 2) {\n var half = n>>1;\n var sieve = Array(half);\n for (var i = 1, limit = Math.sqrt(n)>>1; i <= limit; i++) {\n if (!sieve[i]) {\n for (var step = 2*i+1, j = (step*step)>>1; j < half; j+=step) {\n sieve[j] = true;\n }\n }\n }\n primes.push(2);\n for (var p = 1; p < half; p++) {\n if (!sieve[p]) primes.push(2*p+1);\n }\n }\n return primes;\n}\n\nfunction sumPrimes(num) {\n return eratosthenesArray(num+1).reduce(function(a,b) {return a+b;}, 0);\n}\n\nsumPrimes(10);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -547,11 +633,10 @@
{
"id": "ae9defd7acaf69703ab432ea",
"title": "Smallest Common Multiple",
"difficulty": "2.11",
"description": [
"Find the smallest number that is evenly divisible by all numbers in the provided range.",
"In other words, given the range [3,7], you will need to find the least common multiple of 3, 4, 5, 6, and 7.",
"Find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters.",
"The range will be an array of two numbers that will not necessarily be in numerical order.",
"e.g. for 1 and 3 - find the smallest common multiple of both 1 and 3 that is evenly divisible by all numbers <em>between</em> 1 and 3.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
@ -563,14 +648,17 @@
"smallestCommons([1,5]);"
],
"tests": [
"expect(smallestCommons([1,5])).to.be.a('number');",
"expect(smallestCommons([1,5])).to.equal(60);",
"expect(smallestCommons([5,1])).to.equal(60);",
"expect(smallestCommons([1,13])).to.equal(360360);"
"assert.deepEqual(typeof(smallestCommons([1, 5])), \"number\", 'message: <code>smallestCommons()</code> should return a number.');",
"assert.deepEqual(smallestCommons([1, 5]), 60, 'message: <code>smallestCommons([1, 5])</code> should return 60.');",
"assert.deepEqual(smallestCommons([5, 1]), 60, 'message: <code>smallestCommons([5, 1])</code> should return 60.');",
"assert.deepEqual(smallestCommons([1, 13]), 360360, 'message: <code>smallestCommons([1, 13])</code> should return 360360.');"
],
"MDNlinks": [
"Smallest Common Multiple"
],
"solutions": [
"function gcd(a, b) {\n while (b !== 0) {\n a = [b, b = a % b][0];\n }\n return a;\n}\n\nfunction lcm(a, b) {\n return (a * b) / gcd(a, b);\n}\n\nfunction smallestCommons(arr) {\n arr.sort(function(a,b) {return a-b;});\n var rng = [];\n for (var i = arr[0]; i <= arr[1]; i++) {\n rng.push(i);\n }\n return rng.reduce(lcm);\n}\n\n\nsmallestCommons([1,5]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -587,7 +675,6 @@
{
"id": "a6e40f1041b06c996f7b2406",
"title": "Finders Keepers",
"difficulty": "2.12",
"description": [
"Create a function that looks through an array (first argument) and returns the first element in the array that passes a truth test (second argument).",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -601,11 +688,14 @@
"find([1, 2, 3, 4], function(num){ return num % 2 === 0; });"
],
"tests": [
"assert.strictEqual(find([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, 'should return first found value');",
"assert.strictEqual(find([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'should return undefined if not found');"
"assert.strictEqual(find([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; }), 8, 'message: <code>find([1, 3, 5, 8, 9, 10], function(num) { return num % 2 === 0; })</code> should return 8.');",
"assert.strictEqual(find([1, 3, 5, 9], function(num) { return num % 2 === 0; }), undefined, 'message: <code>find([1, 3, 5, 9], function(num) { return num % 2 === 0; })</code> should return undefined.');"
],
"MDNlinks": [
"Array.some()"
"Array.filter()"
],
"solutions": [
"function find(arr, func) {\n var num;\n arr.some(function(e) {\n if (func(e)) {\n num = e;\n return true;\n }\n });\n return num;\n}\n\nfind([1, 2, 3, 4], function(num){ return num % 2 === 0; });\n"
],
"type": "bonfire",
"challengeType": 5,
@ -623,7 +713,6 @@
{
"id": "a5deed1811a43193f9f1c841",
"title": "Drop it",
"difficulty": "2.13",
"description": [
"Drop the elements of an array (first argument), starting from the front, until the predicate (second argument) returns true.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -637,14 +726,18 @@
"drop([1, 2, 3], function(n) {return n < 3; });"
],
"tests": [
"expect(drop([1, 2, 3, 4], function(n) {return n >= 3; })).to.eqls([3, 4]);",
"expect(drop([1, 2, 3], function(n) {return n > 0; })).to.eqls([1, 2, 3]);",
"expect(drop([1, 2, 3, 4], function(n) {return n > 5; })).to.eqls([]);"
"assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n>= 3;}), [3, 4], 'message: <code>drop([1, 2, 3, 4], function(n) {return n >= 3;})</code> should return <code>[3, 4]</code>.');",
"assert.deepEqual(drop([1, 2, 3], function(n) {return n > 0; }), [1, 2, 3], 'message: <code>drop([1, 2, 3], function(n) {return n > 0; })</code> should return <code>[1, 2, 3]</code>.');",
"assert.deepEqual(drop([1, 2, 3, 4], function(n) {return n > 5;}), [], 'message: <code>drop([1, 2, 3, 4], function(n) {return n > 5;})</code> should return <code>[]</code>.');",
"assert.deepEqual(drop([1, 2, 3, 7, 4], function(n) {return n > 3}), [7, 4], 'message: <code>drop([1, 2, 3, 7, 4], function(n) {return n > 3})</code> should return <code>[7, 4]</code>.');"
],
"MDNlinks": [
"Arguments object",
"Array.shift()"
],
"solutions": [
"(function drop(arr, func) {\n // Drop them elements.\n while (arr.length && !func(arr[0])) {\n arr.shift();\n }\n return arr;\n}\n\ndrop([1, 2, 3], function(n) {return n < 3; });\n)"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -661,7 +754,6 @@
{
"id": "ab306dbdcc907c7ddfc30830",
"title": "Steamroller",
"difficulty": "2.14",
"description": [
"Flatten a nested array. You must account for varying levels of nesting.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
@ -675,14 +767,17 @@
"steamroller([1, [2], [3, [[4]]]]);"
],
"tests": [
"assert.deepEqual(steamroller([[['a']], [['b']]]), ['a', 'b'], 'should flatten nested arrays');",
"assert.deepEqual(steamroller([1, [2], [3, [[4]]]]), [1, 2, 3, 4], 'should flatten nested arrays');",
"assert.deepEqual(steamroller([1, [], [3, [[4]]]]), [1, 3, 4], 'should work with empty arrays');",
"assert.deepEqual(steamroller([1, {}, [3, [[4]]]]), [1, {}, 3, 4], 'should work with actual objects');"
"assert.deepEqual(steamroller([[[\"a\"]], [[\"b\"]]]), [\"a\", \"b\"], 'message: <code>steamroller([[[\"a\"]], [[\"b\"]]])</code> should return <code>[\"a\", \"b\"]</code>.');",
"assert.deepEqual(steamroller([1, [2], [3, [[4]]]]), [1, 2, 3, 4], 'message: <code>steamroller([1, [2], [3, [[4]]]])</code> should return <code>[1, 2, 3, 4]</code>.');",
"assert.deepEqual(steamroller([1, [], [3, [[4]]]]), [1, 3, 4], 'message: <code>steamroller([1, [], [3, [[4]]]])</code> should return <code>[1, 3, 4]</code>.');",
"assert.deepEqual(steamroller([1, {}, [3, [[4]]]]), [1, {}, 3, 4], 'message: <code>steamroller([1, {}, [3, [[4]]]])</code> should return <code>[1, {}, 3, 4]</code>.');"
],
"MDNlinks": [
"Array.isArray()"
],
"solutions": [
"function steamroller(arr) {\n if (!Array.isArray(arr)) {\n return [arr];\n }\n var out = [];\n arr.forEach(function(e) {\n steamroller(e).forEach(function(v) {\n out.push(v);\n });\n });\n return out;\n}\n\nsteamroller([1, [2], [3, [[4]]]]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -699,7 +794,6 @@
{
"id": "a8d97bd4c764e91f9d2bda01",
"title": "Binary Agents",
"difficulty": "2.15",
"description": [
"Return an English translated sentence of the passed binary string.",
"The binary string will be space separated.",
@ -710,16 +804,19 @@
" return str;",
"}",
"",
"binaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111');"
"binaryAgent(\"01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111\");"
],
"tests": [
"expect(binaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111')).to.equal(\"Aren't bonfires fun!?\");",
"expect(binaryAgent('01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001')).to.equal(\"I love FreeCodeCamp!\");"
"assert.deepEqual(binaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111'), \"Aren't bonfires fun!?\", 'message: <code>binaryAgent(\"01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111\")</code> should return \"Aren&#39;t bonfires fun!?\"');",
"assert.deepEqual(binaryAgent(\"01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001\"), \"I love FreeCodeCamp!\", 'message: <code>binaryAgent(\"01001001 00100000 01101100 01101111 01110110 01100101 00100000 01000110 01110010 01100101 01100101 01000011 01101111 01100100 01100101 01000011 01100001 01101101 01110000 00100001\"</code> should return \"I love FreeCodeCamp!\"');"
],
"MDNlinks": [
"String.charCodeAt()",
"String.fromCharCode()"
],
"solutions": [
"function binaryAgent(str) {\n return str.split(' ').map(function(s) { return parseInt(s, 2); }).map(function(b) { return String.fromCharCode(b);}).join('');\n}\n\nbinaryAgent('01000001 01110010 01100101 01101110 00100111 01110100 00100000 01100010 01101111 01101110 01100110 01101001 01110010 01100101 01110011 00100000 01100110 01110101 01101110 00100001 00111111');\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -736,29 +833,32 @@
{
"id": "a10d2431ad0c6a099a4b8b52",
"title": "Everything Be True",
"difficulty": "2.21",
"description": [
"Check if the predicate (second argument) returns truthy (defined) for all elements of a collection (first argument).",
"For this, check to see if the property defined in the second argument is present on every element of the collection.",
"Check if the predicate (second argument) is truthy on all elements of a collection (first argument).",
"Remember, you can access object properties through either dot notation or [] notation.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
"challengeSeed": [
"function every(collection, pre) {",
" // Does everyone have one of these?",
" // Is everyone being true?",
" return pre;",
"}",
"",
"every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');"
"every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\");"
],
"tests": [
"assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex'), true, 'should return true if predicate returns truthy for all elements in the collection');",
"assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], {'sex': 'female'}), false, 'should return false if predicate returns falsey for any element in the collection');",
"assert.strictEqual(every([{'user': 'Tinky-Winky', 'sex': 'female'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], {'sex': 'female'}), false, 'should return false if predicate returns falsey for any element in the collection');"
"assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\"), true, 'message: <code>every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\", \"sex\": \"male\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\")</code> should return true.');",
"assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\"), false, 'message: <code>every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\"}, {\"user\": \"Dipsy\"}, {\"user\": \"Laa-Laa\", \"sex\": \"female\"}, {\"user\": \"Po\", \"sex\": \"female\"}], \"sex\")</code> should return false.');",
"assert.strictEqual(every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\", \"age\": 2}, {\"user\": \"Dipsy\", \"sex\": \"male\", \"age\": 0}, {\"user\": \"Laa-Laa\", \"sex\": \"female\", \"age\": 5}, {\"user\": \"Po\", \"sex\": \"female\", \"age\": 4}], \"age\"), false, 'message: <code>every([{\"user\": \"Tinky-Winky\", \"sex\": \"male\", \"age\": 0}, {\"user\": \"Dipsy\", \"sex\": \"male\", \"age\": 3}, {\"user\": \"Laa-Laa\", \"sex\": \"female\", \"age\": 5}, {\"user\": \"Po\", \"sex\": \"female\", \"age\": 4}], \"age\")</code> should return false.');",
"assert.strictEqual(every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true}, {\"name\": \"FastFoward\", \"onBoat\": null}], \"onBoat\"), false, 'message: <code>every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true}, {\"name\": \"FastFoward\", \"onBoat\": null}], \"onBoat\")</code> should return false');",
"assert.strictEqual(every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true, \"alias\": \"Repete\"}, {\"name\": \"FastFoward\", \"onBoat\": true}], \"onBoat\"), true, 'message: <code>every([{\"name\": \"Pete\", \"onBoat\": true}, {\"name\": \"Repeat\", \"onBoat\": true, \"alias\": \"Repete\"}, {\"name\": \"FastFoward\", \"onBoat\": true}], \"onBoat\")</code> should return true');",
"assert.strictEqual(every([{\"single\": \"yes\"}], \"single\"), true, 'message: <code>every([{\"single\": \"yes\"}], \"single\")</code> should return true');",
"assert.strictEqual(every([{\"single\": \"\"}, {\"single\": \"double\"}], \"single\"), false, 'message: <code>every([{\"single\": \"\"}, {\"single\": \"double\"}], \"single\")</code> should return false');",
"assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": undefined}], \"single\"), false, 'message: <code>every([{\"single\": \"double\"}, {\"single\": undefined}], \"single\")</code> should return false');",
"assert.strictEqual(every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\"), false, 'message: <code>every([{\"single\": \"double\"}, {\"single\": NaN}], \"single\")</code> should return false');"
],
"MDNlinks": [
"Object.hasOwnProperty()",
"Object.getOwnPropertyNames()"
"solutions": [
"function every(collection, pre) {\n // Does everyone have one of these?\n return collection.every(function(e) { return e[pre]; });\n}\n\nevery([{'user': 'Tinky-Winky', 'sex': 'male'}, {'user': 'Dipsy', 'sex': 'male'}, {'user': 'Laa-Laa', 'sex': 'female'}, {'user': 'Po', 'sex': 'female'}], 'sex');\n"
],
"type": "bonfire",
"challengeType": 5,
@ -776,10 +876,12 @@
{
"id": "a97fd23d9b809dac9921074f",
"title": "Arguments Optional",
"difficulty": "2.22",
"description": [
"Create a function that sums two arguments together. If only one argument is provided, return a function that expects one additional argument and will return the sum.",
"For example, add(2, 3) should return 5, and add(2) should return a function that is waiting for an argument so that <code>var sum2And = add(2); return sum2And(3); // 5</code>",
"Create a function that sums two arguments together. If only one argument is provided, then return a function that expects one argument and returns the sum.",
"For example, <code>add(2, 3)</code> should return <code>5</code>, and <code>add(2)</code> should return a function.",
"Calling this returned function with a single argument will then return the sum:",
"<code>var sumTwoAnd = add(2);</code>",
"<code>sumTwoAnd(3)</code> returns <code>5</code>.",
"If either argument isn't a valid number, return undefined.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' target='_blank'>Read-Search-Ask</a> if you get stuck. Try to pair program. Write your own code."
],
@ -791,16 +893,20 @@
"add(2,3);"
],
"tests": [
"expect(add(2, 3)).to.equal(5);",
"expect(add(2)(3)).to.equal(5);",
"expect(add('http://bit.ly/IqT6zt')).to.be.undefined;",
"expect(add(2, '3')).to.be.undefined;",
"expect(add(2)([3])).to.be.undefined;"
"assert.deepEqual(add(2, 3), 5, 'message: <code>add(2, 3)</code> should return 5.');",
"assert.deepEqual(add(2)(3), 5, 'message: <code>add(2)(3)</code> should return 5.');",
"assert.isUndefined(add(\"http://bit.ly/IqT6zt\"), 'message: <code>add(\"http://bit.ly/IqT6zt\")</code> should return undefined.');",
"assert.isUndefined(add(2, \"3\"), 'message: <code>add(2, \"3\")</code> should return undefined.');",
"assert.isUndefined(add(2)([3]), 'message: <code>add(2)([3])</code> should return undefined.');"
],
"MDNlinks": [
"Global Function Object",
"Closures",
"Arguments object"
],
"solutions": [
"function add() {\n if (arguments.length == 1) {\n var a = arguments[0];\n if (!isNumber(a)) return;\n return function(b) {\n if (!isNumber(b)) return;\n return a+b;\n };\n }\n if (![].slice.call(arguments).every(isNumber)) return;\n return arguments[0] + arguments[1];\n}\n \nfunction isNumber(obj) {\n return toString.call(obj) == '[object Number]';\n}\n\nadd(2,3);\n",
"function add() {\n var a = arguments[0];\n if (toString.call(a) !== '[object Number]') return; \n if (arguments.length === 1) {\n return function(b) {\n if (toString.call(b) !== '[object Number]') return;\n return a + b;\n };\n }\n var b = arguments[1];\n if (toString.call(b) !== '[object Number]') return; \n return a + arguments[1];\n}\n\nadd(2,3);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",

View File

@ -1,26 +1,125 @@
{
"name": "Intermediate Front End Development Projects",
"order": 0.015,
"order": 11,
"time": "200h",
"challenges": [
{
"id": "bd7158d8c442eddfaeb5bd10",
"title": "Show the Local Weather",
"challengeSeed": ["126415127"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/FreeCodeCamp/pen/avqvgJ' target='_blank'>http://codepen.io/FreeCodeCamp/pen/avqvgJ</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can see the weather in my current location.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can see an icon depending on the weather.",
"<span class='text-info'>Bonus User Story:</span> As a user, I see a different background image (e.g. snowy mountain, hot desert) depending on the weather.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can push a button to toggle between Fahrenheit and Celsius.",
"We recommend using the <a href='http://openweathermap.org/current#geo' target='_blank'>Open Weather API</a>. This will require creating a free API key. Normally you want to avoid exposing API keys on CodePen, but we haven't been able to find a keyless API for weather.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "Покажите местную погоду",
"descriptionRu": [
"<span class='text-info'>Задание:</span> Создайте <a href='http://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='http://codepen.io/AdventureBear/full/yNBJRj' target='_blank'>http://codepen.io/AdventureBear/full/yNBJRj</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='http://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='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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>"
],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c442eddfaeb5bd1f",
"title": "Use the Twitch.tv JSON API",
"challengeSeed": ["126411564"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/GJKRxZ' target='_blank'>http://codepen.io/GeoffStorbeck/full/GJKRxZ</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can see whether Free Code Camp is currently streaming on Twitch.tv.",
"<span class='text-info'>User Story:</span> As a user, I can click the status output and be sent directly to the Free Code Camp's Twitch.tv channel.",
"<span class='text-info'>User Story:</span> As a user, if Free Code Camp is streaming, I can see additional details about what they are streaming.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can search through the streams listed.",
"<span class='text-info'>Bonus User Story:</span> As a user, I will see a placeholder notification if a streamer has closed their Twitch account. You can verify this works by adding brunofin and comster404 to your array of Twitch streamers.",
"<span class='text-info'>Hint:</span> Here's an example call to Twitch.tv's JSON API: <code>https://api.twitch.tv/kraken/streams/freecodecamp</code>.",
"<span class='text-info'>Hint:</span> The relevant documentation about this API call is here: <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'>Hint:</span> Here's an array of the Twitch.tv usernames of people who regularly stream coding: <code>[\"freecodecamp\", \"storbeck\", \"terakilobyte\", \"habathcx\",\"RobotCaleb\",\"thomasballinger\",\"noobs2ninjas\",\"beohoff\"]</code>",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "Используйте Twitch.tv JSON API",
"descriptionRu": [
"<span class='text-info'>Задание:</span> Создайте <a href='http://codepen.io' target='_blank'>CodePen.io</a> который успешно копирует вот этот: <a href='http://codepen.io/GeoffStorbeck/full/GJKRxZ' target='_blank'>http://codepen.io/GeoffStorbeck/full/GJKRxZ</a>.",
"<span class='text-info'>Правило #1:</span> Не подсматривайте код приведенного на CodePen примера. Напишите его самостоятельно.",
"<span class='text-info'>Правило #2:</span> Можете использовать любые библиотеки или API, которые потребуются.",
"<span class='text-info'>Правило #3:</span> Воссоздайте функционал приведенного примера и не стесняйтесь добавить что-нибудь от себя.",
"Реализуйте следующие <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>пользовательские истории</a>, сделайте также бонусные по желанию:",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу увидеть идет ли в данный момент на Twitch.tv трансляция Free Code Camp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу, кликнув на описание трансляции, перейти на канал Free Code Camp.",
"<span class='text-info'>Пользовательская история:</span> В качестве пользователя, я могу видеть дополнительную информацию о текущей трансляции Free Code Camp.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу произвести поиск среди перечисленных каналов.",
"<span class='text-info'>Бонусная пользовательская история:</span> В качестве пользователя, я могу видеть уведомление, если создатель канала закрыл свой аккаунт на Twitch.tv. Добавьте в массив имена пользователей brunofin и comster404, чтобы убедиться, что эта функция реализована правильно.",
"<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>[\"freecodecamp\", \"storbeck\", \"terakilobyte\", \"habathcx\",\"RobotCaleb\",\"comster404\",\"brunofin\",\"thomasballinger\",\"noobs2ninjas\",\"beohoff\"]</code>",
"Если что-то не получается, воспользуйтесь <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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>"
],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c442eddfaeb5bd18",
"title": "Stylize Stories on Camper News",
"difficulty": 1.02,
"challengeSeed": ["126415129"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/Wveezv' target='_blank'>http://codepen.io/GeoffStorbeck/full/Wveezv</a>.",
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/MarufSarker/full/ZGPZLq/' target='_blank'>http://codepen.io/MarufSarker/full/ZGPZLq/</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can browse recent posts from Camper News.",
"<span class='text-info'>User Story:</span> As a user, I can click on a post to be taken to the story's original URL.",
"<span class='text-info'>User Story:</span> As a user, I can click a link to go directly to the post's discussion page.",
"<span class='text-info'>Bonus User Story:</span> As a user, I can see how many upvotes each story has.",
"<span class='text-info'>Hint:</span> Here's the Camper News Hot Stories API endpoint: <code>http://www.freecodecamp.com/news/hot</code>.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -38,8 +137,7 @@
},
{
"id": "bd7158d8c442eddfaeb5bd19",
"title": "Wikipedia Viewer",
"difficulty": 1.03,
"title": "Build a Wikipedia Viewer",
"challengeSeed": ["126415131"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/MwgQea' target='_blank'>http://codepen.io/GeoffStorbeck/full/MwgQea</a>.",
@ -53,39 +151,7 @@
"<span class='text-info'>Hint:</span> Here's an entry on using Wikipedia's API: <code>http://www.mediawiki.org/wiki/API:Main_page</code>.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
],
"type": "zipline",
"challengeType": 3,
"tests": [],
"nameCn": "",
"descriptionCn": [],
"nameFr": "",
"descriptionFr": [],
"nameRu": "",
"descriptionRu": [],
"nameEs": "",
"descriptionEs": [],
"namePt": "",
"descriptionPt": []
},
{
"id": "bd7158d8c442eddfaeb5bd17",
"title": "Build a JavaScript Calculator",
"difficulty": 1.05,
"challengeSeed": ["126411565"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/GeoffStorbeck/full/zxgaqw' target='_blank'>http://codepen.io/GeoffStorbeck/full/zxgaqw</a>.",
"<span class='text-info'>Rule #1:</span> Don't look at the example project's code on CodePen. Figure it out for yourself.",
"<span class='text-info'>Rule #2:</span> You may use whichever libraries or APIs you need.",
"<span class='text-info'>Rule #3:</span> Reverse engineer the example project's functionality, and also feel free to personalize it.",
"Here are the <a href='http://en.wikipedia.org/wiki/User_story' target='_blank'>user stories</a> you must enable, and optional bonus user stories:",
"<span class='text-info'>User Story:</span> As a user, I can add, subtract, multiply and divide two numbers.",
"<span class='text-info'>Bonus User Story:</span> I can clear the input field with a clear button.",
"<span class='text-info'>Bonus User Story:</span> I can keep chaining mathematical operations together until I hit the clear button, and the calculator will tell me the correct output.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -104,7 +170,6 @@
{
"id": "bd7158d8c442eedfaeb5bd1c",
"title": "Build a Tic Tac Toe Game",
"difficulty": 1.06,
"challengeSeed": ["126415123"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/alex-dixon/full/JogOpQ/' target='_blank'>http://codepen.io/alex-dixon/full/JogOpQ/</a>.",
@ -118,7 +183,7 @@
"<span class='text-info'>Bonus User Story:</span> As a user, I can choose whether I want to play as X or O.",
"Remember to use <a href='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,
@ -137,7 +202,6 @@
{
"id": "bd7158d8c442eddfaeb5bd1c",
"title": "Build a Simon Game",
"difficulty": 1.07,
"challengeSeed": ["137213633"],
"description": [
"<span class='text-info'>Objective:</span> Build a <a href='http://codepen.io' target='_blank'>CodePen.io</a> app that successfully reverse-engineers this: <a href='http://codepen.io/Em-Ant/full/QbRyqq/' target='_blank'>http://codepen.io/dting/full/QbRyqq/</a>.",
@ -157,7 +221,7 @@
"<span class='text-info'>Hint:</span> 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='//github.com/FreeCodeCamp/freecodecamp/wiki/How-to-get-help-when-you-get-stuck' 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. If you pair programmed, you should also include the Free Code Camp username of your pair.",
"If you'd like immediate feedback on your project, click this button and paste in a link to your CodePen project. Otherwise, we'll review it before you start your nonprofit projects.<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>"
"If you'd like immediate feedback on your project from fellow campers, click this button and paste in a link to your CodePen project. <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:%20PASTE_YOUR_CODEPEN_URL_HERE%20%0A%20%23LearnToCode%20%23JavaScript' target='_blank'>Click here then add your link to your tweet's text</a>"
],
"type": "zipline",
"challengeType": 3,

View File

@ -1,28 +1,29 @@
{
"name": "jQuery",
"order": 0.004,
"order": 5,
"time": "2h",
"challenges": [
{
"id": "bad87fee1348bd9acdd08826",
"title": "Learn how Script Tags and Document Ready Work",
"difficulty": 3.01,
"description": [
"Now we're ready to learn jQuery, the most popular JavaScript tool of all time. Don't worry about JavaScript itself - we will cover it soon.",
"Before we can start using jQuery, we need to add some things to our HTML.",
"First, add a <code>script</code> element at the top of your page. Be sure to close it on the following line.",
"Your browser will run any JavaScript inside a <code>script</code> element, including jQuery.",
"Inside your <code>script</code> element, add this code: <code>$(document).ready(function() {</code> to your <code>script</code>. Then close it on the following line (still inside your <code>script</code> element) with: <code>});</code>"
"Inside your <code>script</code> element, add this code: <code>$(document).ready(function() {</code> to your <code>script</code>. Then close it on the following line (still inside your <code>script</code> element) with: <code>});</code>",
"We'll learn more about <code>functions</code> later. The important thing to know is that code you put inside this <code>function</code> will run as soon as your browser has loaded your page.",
"This is important because without your <code>document ready function</code>, your code may run before your HTML is rendered, which would cause bugs."
],
"tests": [
"assert(editor.match(/<script>/g), 'Create a <code>script</code> element.')",
"assert(editor.match(/<\\/script>/g) && editor.match(/<script/g) && editor.match(/<\\/script>/g).length === editor.match(/<script/g).length, 'Make sure your <code>script</code> element has a closing tag.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?document\\)\\.ready\\s*?\\(\\s*?function\\s*?\\(\\s*?\\)\\s*?\\{/g), 'Add <code>$(document).ready(function() {</code> to the beginning of your <code>script</code> element.')",
"assert(editor.match(/\\n*?\\s*?\\}\\s*?\\);/g), 'Close your <code>$(document).ready(function() {</code> function with <code>});</code>.')"
"assert(editor.match(/<\\/script\\s*>/g) && editor.match(/<script(\\sasync|\\sdefer)*(\\s(charset|src|type)\\s*=\\s*[\"\\']+[^\"\\']*[\"\\']+)*(\\sasync|\\sdefer)*\\s*>/g) && editor.match(/<\\/script\\s*>/g).length === editor.match(/<script(\\sasync|\\sdefer)*(\\s(charset|src|type)\\s*=\\s*[\"\\']+[^\"\\']*[\"\\']+)*(\\sasync|\\sdefer)*\\s*>/g).length, 'Create a <code>script</code> element making sure it is valid and has a closing tag.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?document\\)\\.ready\\s*?\\(\\s*?function\\s*?\\(\\s*?\\)\\s*?\\{/g), 'You should add <code>$&#40;document&#41;.ready&#40;function&#40;&#41; {</code> to the beginning of your <code>script</code> element.')",
"assert(editor.match(/\\n*?\\s*?\\}\\s*?\\);/g), 'Close your <code>$&#40;document&#41;.ready&#40;function&#40;&#41; {</code> function with <code>}&#41;;</code>')"
],
"challengeSeed": [
"",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -52,13 +53,12 @@
{
"id": "bad87fee1348bd9bedc08826",
"title": "Target HTML Elements with Selectors Using jQuery",
"difficulty": 3.02,
"description": [
"Now we have a <code>document ready function</code>. We'll learn more about <code>functions</code> later. The important thing to know is that code you put inside this <code>function</code> will run as soon as your browser has loaded your page.",
"This is important because without your <code>document ready function</code>, your code may run before your HTML is rendered, which would cause bugs.",
"Now we have a <code>document ready function</code>.",
"Now let's write our first jQuery statement. All jQuery functions start with a <code>$</code>, usually referred to as a <code>dollar sign operator</code>, or simply as <code>bling</code>.",
"jQuery often selects an HTML element with a <code>selector</code>, then does something to that element.",
"For example, let's make all of your <code>button</code> elements bounce. Just add this code inside your <code>document ready function</code>: <code>$(\"button\").addClass(\"animated bounce\")</code>.",
"For example, let's make all of your <code>button</code> elements bounce. Just add this code inside your document ready function:",
"<code>$(\"button\").addClass(\"animated bounce\")</code>",
"Note that we've already included both the jQuery library and the Animate.css library in your code editor. So you are using jQuery to apply the Animate.css <code>bounce</code> class to your <code>button</code> elements."
],
"tests": [
@ -72,7 +72,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -102,14 +102,14 @@
{
"id": "bad87fee1348bd9aedc08826",
"title": "Target Elements by Class Using jQuery",
"difficulty": 3.03,
"description": [
"You see how we made all of your <code>button</code> elements bounce? We selected them with <code>$(\"button\")</code>, then we added some CSS classes to them with <code>.addClass(\"animated bounce\");</code>.",
"You just used jQuery's <code>.addClass()</code> function, which allows you to add classes to elements.",
"First, let's target your <code>div</code> elements with the class <code>well</code> by using the <code>$(\".well\")</code> selector.",
"Note that, just like with CSS declarations, you type a <code>.</code> before the class's name.",
"Then use jQuery's <code>.addClass()</code> function to add the classes <code>animated</code> and <code>shake</code>.",
"For example, you could make all the elements with the class <code>text-primary</code> shake by adding the following to your <code>document ready function</code>: <code>$(\".text-primary\").addClass(\"animated shake\");</code>"
"For example, you could make all the elements with the class <code>text-primary</code> shake by adding the following to your <code>document ready function</code>:",
"<code>$(\".text-primary\").addClass(\"animated shake\");</code>"
],
"tests": [
"assert($(\".well\").hasClass(\"animated\") && $(\".well\").hasClass(\"shake\"), 'Use the jQuery <code>addClass&#40&#41</code> function to give the classes <code>animated</code> and <code>shake</code> to all your elements with the class <code>well</code>.')",
@ -122,7 +122,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -152,17 +152,17 @@
{
"id": "bad87fee1348bd9aeda08826",
"title": "Target Elements by ID Using jQuery",
"difficulty": 3.04,
"description": [
"You can also target elements by their id attributes.",
"First target your <code>button</code> element with the id <code>target3</code> by using the <code>$(\"#target3\")</code> selector.",
"Note that, just like with CSS declarations, you type a <code>#</code> before the id's name.",
"Then use jQuery's <code>.addClass()</code> function to add the classes <code>animated</code> and <code>fadeOut</code>.",
"Here's how you'd make the <code>button</code> element with the id <code>target6</code> fade out: <code>$(\"#target6\").addClass(\"animated fadeOut\")</code>."
"Here's how you'd make the <code>button</code> element with the id <code>target6</code> fade out:",
"<code>$(\"#target6\").addClass(\"animated fadeOut\")</code>."
],
"tests": [
"assert($(\"#target3\").hasClass(\"animated\"), 'Select the <code>button</code>element with the <code>id</code> of <code>target3</code> and use the jQuery <code>addClass&#40&#41</code> function to give it the class of <code>animated</code>.');",
"assert($(\"#target3\").hasClass(\"fadeOut\") || $(\"#target3\").hasClass(\"fadeout\"), 'Target the element with the id <code>target3</code> and use the jQuery <code>addClass&#40&#41</code> function to give it the class <code>fadeOut</code>.')",
"assert($(\"#target3\").hasClass(\"animated\"), 'Select the <code>button</code>element with the <code>id</code> of <code>target3</code> and use the jQuery <code>addClass&#40&#41</code> function to give it the class of <code>animated</code>.')",
"assert(($(\"#target3\").hasClass(\"fadeOut\") || $(\"#target3\").hasClass(\"fadeout\")) && editor.match(/\\$\\(.#target3.\\)/g), 'Target the element with the id <code>target3</code> and use the jQuery <code>addClass&#40&#41</code> function to give it the class <code>fadeOut</code>.')",
"assert(!editor.match(/class.*animated/g), 'Only use jQuery to add these classes to the element.')"
],
"challengeSeed": [
@ -174,7 +174,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -204,7 +204,6 @@
{
"id": "bad87fee1348bd9aeda08726",
"title": "Delete your jQuery Functions",
"difficulty": 3.05,
"description": [
"These animations were cool at first, but now they're getting kind of distracting.",
"Delete all three of these jQuery functions from your <code>document ready function</code>, but leave your <code>document ready function</code> itself intact."
@ -213,7 +212,7 @@
"assert(!editor.match(/e\"\\);/g) && !editor.match(/t\"\\);/g), 'Delete all three of your jQuery functions from your <code>document ready function</code>.')",
"assert(editor.match(/<script>/g), 'Leave your <code>script</code> element intact.')",
"assert(editor.match(/\\$\\(document\\)\\.ready\\(function\\(\\)\\s?\\{/g), 'Leave your <code>$&#40document&#41.ready&#40function&#40&#41 {</code> to the beginning of your <code>script</code> element.')",
"assert(editor.match(/\\n\\s+?\\}\\);/g), 'Leave your \"document ready function\" closing <code>\\}&#41;</code> intact.')",
"assert(editor.match(/\\n\\s+?\\}\\);/g), 'Leave your \"document ready function\" closing <code>&#125;&#41;</code> intact.')",
"assert(editor.match(/<\\/script>/g) && editor.match(/<script/g) && editor.match(/<\\/script>/g).length === editor.match(/<script/g).length, 'Leave your <code>script</code> element closing tag intact.')"
],
"challengeSeed": [
@ -226,7 +225,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -256,16 +255,17 @@
{
"id": "bad87fee1348bd9aed908626",
"title": "Target the same element with multiple jQuery Selectors",
"difficulty": 3.06,
"description": [
"Now you know three ways of targeting elements: by type: <code>$(\"button\")</code>, by class: <code>$(\".btn\")</code>, and by id <code>$(\"#target1\")</code>.",
"Use each of these jQuery selectors to target your <code>button</code> element with the class <code>btn</code> and the id <code>target1</code>.",
"Use the <code>addClass()</code> jQuery function to give the element one new class for each selector: <code>animated</code>, <code>shake</code>, and <code>btn-primary</code>."
"Using each of the above jQuery selectors and the <code>addClass()</code> function:",
"Add the <code>animated</code> class to all elements with type <code>button</code>.",
"Add the <code>shake</code> class to all the buttons with class <code>.btn</code>.",
"Add the <code>btn-primary</code> class to the button with id <code>#target1</code>."
],
"tests": [
"assert(editor.match(/\\$\\(.*button/g), 'Use the <code>$&#40\"button\"&#41</code> selector.')",
"assert(editor.match(/\\$\\(.*\\.btn/g), 'Use the <code>$&#40\".btn\"&#41</code> selector.')",
"assert(editor.match(/\\$\\(.*#target1/g), 'Use the <code>$&#40\"#target1\"&#41</code> selector.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\s*?button\\s*?(?:'|\")/gi), 'Use the <code>$&#40\"button\"&#41</code> selector.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\s*?\\.btn\\s*?(?:'|\")/gi), 'Use the <code>$&#40\".btn\"&#41</code> selector.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\s*?#target1\\s*?(?:'|\")/gi), 'Use the <code>$&#40\"#target1\"&#41</code> selector.')",
"assert(editor.match(/addClass/g) && editor.match(/addClass/g).length > 2, 'Only add one class with each of your three selectors.')",
"assert($(\"#target1\").hasClass(\"animated\") && $(\"#target1\").hasClass(\"shake\") && $(\"#target1\").hasClass(\"btn-primary\"), 'Your <code>#target1</code> element should have the classes <code>animated</code>&#130; <code>shake</code> and <code>btn-primary</code>.')",
"assert(!editor.match(/class.*animated/g), 'Only use jQuery to add these classes to the element.')"
@ -277,7 +277,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -307,15 +307,16 @@
{
"id": "bad87fee1348bd9aed918626",
"title": "Remove Classes from an element with jQuery",
"difficulty": 3.07,
"description": [
"In the same way you can add classes to an element with jQuery's <code>addClass()</code> function, you can remove them with jQuery's <code>removeClass()</code> function.",
"Let's remove the <code>btn-default</code> class from all of our <code>button</code> elements.",
"Here's how you would do this for a specific button, add <code>$(\"#target2\").removeClass(\"btn-default\");</code>"
"Here's how you would do this for a specific button:",
"<code>$(\"#target2\").removeClass(\"btn-default\");</code>",
"Let's remove the <code>btn-default</code> class from all of our <code>button</code> elements."
],
"tests": [
"assert($(\".btn-default\").length === 0, 'Remove the <code>btn-default</code> class from all of your <code>button</code> elements.')",
"assert(editor.match(/btn btn-default/g), 'Only use jQuery to remove this class from the element.')"
"assert(editor.match(/btn btn-default/g), 'Only use jQuery to remove this class from the element.')",
"assert(editor.match(/\\.[\\v\\s]*removeClass[\\s\\v]*\\([\\s\\v]*('|\")\\s*btn-default\\s*('|\")[\\s\\v]*\\)/gm), 'Only remove the <code>btn-default</code> class.')"
],
"challengeSeed": [
"fccss",
@ -327,7 +328,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -357,14 +358,14 @@
{
"id": "bad87fee1348bd9aed908826",
"title": "Change the CSS of an Element Using jQuery",
"difficulty": 3.08,
"description": [
"We can also change the CSS of an HTML element directly with jQuery.",
"Delete your jQuery selectors, leaving an empty <code>document ready function</code>.",
"Select <code>target1</code> and change its color to red.",
"jQuery has a function called <code>.css()</code> that allows you to change the CSS of an element.",
"Here's how we would change its color to blue: <code>$(\"#target1\").css(\"color\", \"blue\");</code>",
"This is slightly different from a normal CSS declaration, because the CSS property and its value are in quotes, and separated with a comma instead of a colon."
"Here's how we would change its color to blue:",
"<code>$(\"#target1\").css(\"color\", \"blue\");</code>",
"This is slightly different from a normal CSS declaration, because the CSS property and its value are in quotes, and separated with a comma instead of a colon.",
"Delete your jQuery selectors, leaving an empty <code>document ready function</code>.",
"Select <code>target1</code> and change its color to red."
],
"tests": [
"assert($(\"#target1\").css(\"color\") === 'rgb(255, 0, 0)', 'Your <code>target1</code> element should have red text.')",
@ -381,7 +382,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -411,12 +412,12 @@
{
"id": "bad87fee1348bd9aed808826",
"title": "Disable an Element Using jQuery",
"difficulty": 3.09,
"description": [
"You can also change the non-CSS properties of HTML elements with jQuery. For example, you can disable buttons.",
"When you disable a button, it will become grayed-out and can no longer be clicked.",
"jQuery has a function called <code>.prop()</code> that allows you to adjust the properties of elements.",
"Here's how you would disable all buttons: <code>$(\"button\").prop(\"disabled\", true);</code>",
"Here's how you would disable all buttons:",
"<code>$(\"button\").prop(\"disabled\", true);</code>",
"Disable only the <code>target1</code> button."
],
"tests": [
@ -432,7 +433,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -462,7 +463,6 @@
{
"id": "bad87fee1348bd9aed708826",
"title": "Remove an Element Using jQuery",
"difficulty": 3.10,
"description": [
"Now let's remove an HTML element from your page using jQuery.",
"jQuery has a function called <code>.remove()</code> that will remove an HTML element entirely",
@ -481,7 +481,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -511,11 +511,11 @@
{
"id": "bad87fee1348bd9aed608826",
"title": "Use appendTo to Move Elements with jQuery",
"difficulty": 3.11,
"description": [
"Now let's try moving elements from one <code>div</code> to another.",
"jQuery has a function called <code>appendTo()</code> that allows you to select HTML elements and append them to another element.",
"For example, if we wanted to move <code>target4</code> from our right well to our left well, we would use <code>$(\"#target4\").appendTo(\"#left-well\");</code>",
"For example, if we wanted to move <code>target4</code> from our right well to our left well, we would use:",
"<code>$(\"#target4\").appendTo(\"#left-well\");</code>",
"Move your <code>target2</code> element from your <code>left-well</code> to your <code>right-well</code>."
],
"tests": [
@ -533,7 +533,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -563,11 +563,11 @@
{
"id": "bad87fee1348bd9aed508826",
"title": "Clone an Element Using jQuery",
"difficulty": 3.12,
"description": [
"In addition to moving elements, you can also copy them from one place to another.",
"jQuery has a function called <code>clone()</code> that makes a copy of an element.",
"For example, if we wanted to copy <code>target2</code> from our <code>left-well</code> to our <code>right-well</code>, we would use <code>$(\"#target2\").clone().appendTo(\"#right-well\");</code>",
"For example, if we wanted to copy <code>target2</code> from our <code>left-well</code> to our <code>right-well</code>, we would use:",
"<code>$(\"#target2\").clone().appendTo(\"#right-well\");</code>",
"Did you notice this involves sticking two jQuery functions together? This is called <code>function chaining</code> and it's a convenient way to get things done with jQuery.",
"Clone your <code>target5</code> element and append it to your <code>left-well</code>."
],
@ -587,7 +587,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -617,17 +617,18 @@
{
"id": "bad87fee1348bd9aed308826",
"title": "Target the Parent of an Element Using jQuery",
"difficulty": 3.13,
"description": [
"Every HTML element has a <code>parent</code> element from which it <code>inherits</code> properties.",
"For example, your <code>jQuery Playground</code> <code>h3</code> element has the parent element of <code>&#60;div class=\"container-fluid\"&#62</code>, which itself has the parent <code>body</code>.",
"jQuery has a function called <code>parent()</code> that allows you to access the parent of whichever element you've selected.",
"Give the parent of the <code>#target1</code> element background-color of red.",
"Here's an example of how you would use the <code>parent()</code> function: <code>$(\"#left-well\").parent().css(\"background-color\", \"blue\")</code>"
"Here's an example of how you would use the <code>parent()</code> function if you wanted to give the parent element of the <code>left-well</code> element a background color of blue:",
"<code>$(\"#left-well\").parent().css(\"background-color\", \"blue\")</code>",
"Give the parent of the <code>#target1</code> element a background-color of red."
],
"tests": [
"assert($(\"#left-well\").css(\"background-color\") === 'red' || $(\"#left-well\").css(\"background-color\") === 'rgb(255, 0, 0)' || $(\"#left-well\").css(\"background-color\").toLowerCase() === '#ff0000' || $(\"#left-well\").css(\"background-color\").toLowerCase() === '#f00', 'Your <code>left-well</code> element should have a red background.')",
"assert(editor.match(/\\.parent\\(\\)\\.css/g), 'You should use the <code>parent()</code> function to modify this element.')",
"assert(editor.match(/\\.parent\\(\\)\\.css/g), 'You should use the <code>&#46;parent&#40;&#41;</code> function to modify this element.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\s*?#target1\\s*?(?:'|\")\\s*?\\)\\.parent/gi), 'The <code>&#46;parent&#40;&#41;</code> method should be called on the <code>&#35;target1</code> element.')",
"assert(editor.match(/<div class=\"well\" id=\"left-well\">/g), 'Only use jQuery to add these classes to the element.')"
],
"challengeSeed": [
@ -642,7 +643,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -672,16 +673,16 @@
{
"id": "bad87fee1348bd9aed208826",
"title": "Target the Children of an Element Using jQuery",
"difficulty": 3.14,
"description": [
"Many HTML elements have <code>children</code> elements from which <code>inherit</code> their properties.",
"Many HTML elements have <code>children</code> which <code>inherit</code> their properties from their parent HTML elements.",
"For example, every HTML element is a child of your <code>body</code> element, and your \"jQuery Playground\" <code>h3</code> element is a child of your <code>&#60;div class=\"container-fluid\"&#62</code> element.",
"jQuery has a function called <code>children()</code> that allows you to access the children of whichever element you've selected.",
"Give all the children of your <code>#right-well</code> element a color of green.",
"Here's an example of how you would use the <code>children()</code> function: <code>$(\"#left-well\").children().css(\"color\", \"blue\")</code>"
"Here's an example of how you would use the <code>children()</code> function to give the children of your <code>left-well</code> element the color of blue:",
"<code>$(\"#left-well\").children().css(\"color\", \"blue\")</code>",
"Give all the children of your <code>#right-well</code> element a color of green."
],
"tests": [
"assert($(\"#target6\").css(\"color\") === 'rgb(0, 128, 0)', 'Your <code>target6</code> element should have green text.')",
"assert($(\"#right-well\").children().css(\"color\") === 'rgb(0, 128, 0)', 'All children of <code>#right-well</code> should have green text.')",
"assert(editor.match(/\\.children\\(\\)\\.css/g), 'You should use the <code>children&#40&#41</code> function to modify these elements.')",
"assert(editor.match(/<div class=\"well\" id=\"right-well\">/g), 'Only use jQuery to add these classes to the element.')"
],
@ -698,7 +699,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -728,16 +729,16 @@
{
"id": "bad87fee1348bd9aed108826",
"title": "Target a Specific Child of an Element Using jQuery",
"difficulty": 3.15,
"description": [
"You've seen why id attributes are so convenient for targeting with jQuery selectors. But you won't always have such neat ids to work with.",
"Fortunately, jQuery has some other tricks for targeting the right elements.",
"jQuery uses CSS Selectors to target elements. <code>target:nth-child(n)</code> css selector allows you to select all the nth element with the target class or element type.",
"Make the second child in each of your well elements bounce.",
"Here's how you would give the third element in each well bounce: <code>$(\".target:nth-child(3)\").addClass(\"animated bounce\");</code>"
"Here's how you would give the third element in each well bounce:",
"<code>$(\".target:nth-child(3)\").addClass(\"animated bounce\");</code>",
"Make the second child in each of your well elements bounce. You must target the children of element with the <code>target</code> class."
],
"tests": [
"assert($(\".target:nth-child(2)\").hasClass(\"animated\") && $(\".target:nth-child(2)\").hasClass(\"bounce\"), 'The second element in each of your <code>well</code> elements should bounce.')",
"assert($(\".target:nth-child(2)\").hasClass(\"animated\") && $(\".target:nth-child(2)\").hasClass(\"bounce\"), 'The second element in your <code>target</code> elements should bounce.')",
"assert(editor.match(/\\:nth-child\\(/g), 'You should use the <code>&#58;nth-child&#40&#41</code> function to modify these elements.')",
"assert(editor.match(/<button class=\"btn btn-default target\" id=\"target2\">/g), 'Only use jQuery to add these classes to the element.')"
],
@ -755,7 +756,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -785,11 +786,11 @@
{
"id": "bad87fee1348bd9aed008826",
"title": "Target Even Numbered Elements Using jQuery",
"difficulty": 3.16,
"description": [
"You can also target all the even-numbered elements.",
"Here's how you would target all the odd-numbered elements with class <code>target</code> and give them classes: <code>$(\".target:odd\").addClass(\"animated shake\");</code>",
"Try selecting all the even-numbered elements - that is, what your browser will consider even-numbered elements - and giving them the classes of <code>animated</code> and <code>shake</code>."
"Here's how you would target all the odd-numbered elements with class <code>target</code> and give them classes:",
"<code>$(\".target:odd\").addClass(\"animated shake\");</code>",
"Try selecting all the even-numbered elements and giving them the classes of <code>animated</code> and <code>shake</code>."
],
"tests": [
"assert($('.target:even').hasClass('animated') && $('.target:even').hasClass('shake'), 'All the <code>target</code> elements that computer considers even should shake.')",
@ -812,7 +813,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",
@ -842,7 +843,6 @@
{
"id": "bad87fee1348bd9aecb08826",
"title": "Use jQuery to Modify the Entire Page",
"difficulty": 3.20,
"description": [
"We're done playing with our jQuery playground. Let's tear it down!",
"jQuery can target the <code>body</code> element as well.",
@ -869,7 +869,7 @@
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"<!-- Only change code above this line. -->",
"",
"<div class=\"container-fluid\">",
" <h3 class=\"text-primary text-center\">jQuery Playground</h3>",

View File

@ -0,0 +1,404 @@
{
"name": "JSON APIs and Ajax",
"order": 10.5,
"time": "30m",
"challenges": [
{
"id": "bb000000000000000000001",
"title": "Trigger Click Events with jQuery",
"description": [
"In this section, we'll learn how to get data from APIs. APIs - or Application Interfaces - are tools that computers use to communicate with one another.",
"We'll also learn how to update HTML with the data we get from these APIs using a technology called Ajax.",
"First, let's review what the <code>$(document).ready()</code> function does. This function makes it so all code inside of it only runs once our page loads.",
"Let's make our \"Get Message\" button change the text of the element with the class <code>message</code>.",
"Before we can do this, we need to implement a <code>click event</code> inside of our <code>$(document).ready()</code> function by adding this code:",
"<code>$(\"#getMessage\").on(\"click\", function(){</code>",
"",
"<code>});</code>"
],
"tests": [
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\#getMessage(?:'|\")\\s*?\\)\\s*?\\.on\\s*?\\(\\s*?(?:'|\")click(?:'|\")\\s*?\\,\\s*?function\\s*?\\(\\s*?\\)\\s*?\\{/gi), 'Bind the click event to the button with the ID of <code>getMessage</code>')",
"assert(editor.match(/\\n*?\\s*?\\}\\n*?\\s*?\\);/gi) && editor.match(/\\n*?\\s*?\\}\\);/gi).length >= 2, 'Be sure to close your functions with <code>}&#41;;</code>')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" // Only change code below this line.",
" ",
" // Only change code above this line.",
" });",
"fcces",
"",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here",
" </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bc000000000000000000001",
"title": "Change Text with Click Events",
"description": [
"When our click event happens, we can use Ajax to update an HTML element.",
"Let's make it so that when a user clicks the \"Get Message\" button, we change the text of the element with the class <code>message</code> to say \"Here is the message\".",
"We can do this by adding the following code within our click event:",
"<code>&thinsp;&thinsp;$(\".message\").html(\"Here is the message\");</code>"
],
"tests": [
"assert(editor.match(/\\$\\s*?\\(\\s*?(?:'|\")\\.message(?:'|\")\\s*?\\)\\s*?\\.html\\s*?\\(\\s*?(?:'|\")Here\\sis\\sthe\\smessage(?:'|\")\\s*?\\);/gi), 'Clicking the \"Get Message\" button should give the element with the class <code>message</code> the text \"Here is the message\".')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"#getMessage\").on(\"click\", function(){",
" // Only change code below this line.",
"",
" // Only change code above this line.",
" });",
" });",
"fcces",
"",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here",
" </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bb000000000000000000002",
"title": "Get JSON with the jQuery getJSON Method",
"description": [
"You can also request data from an external source. This is where APIs come into play.",
"Remember that APIs - or Application Interfaces - are tools that computers use to communicate with one another.",
"Most web APIs transfer data in a format called JSON. JSON stands for JavaScript Object Notation.",
"You've already been using JSON whenever you create a JavaScript object. JSON is nothing more than 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\".",
"Let's get the JSON from Free Code Camp's Cat Photo API.",
"Here's the code you can put in your click event to do this:",
"<code>&thinsp;&thinsp;$.getJSON(\"/json/cats.json?callback=\", function( json ) {</code>",
"<code>&thinsp;&thinsp;&thinsp;&thinsp;$(\".message\").html(JSON.stringify(json))</code>",
"<code>&thinsp;&thinsp;});</code>",
"Once you've added this, click the \"Get Message\" button. Your Ajax function will replace the \"The message will go here\" text with the raw JSON output from the Free Code Camp Cat Photo API."
],
"tests": [
"assert(editor.match(/\\$\\s*?\\(\\s*?(\\\"|\\')\\#getMessage(\\\"|\\')\\s*?\\)\\s*?\\.\\s*?on\\s*?\\(\\s*?(\\\"|\\')click(\\\"|\\')\\s*?\\,\\s*?function\\s*?\\(\\s*?\\)\\s*?\\{/gi), 'You should have a click handler on the getMessage button to trigger the AJAX request.')",
"assert(editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi), 'You should have at least on closing set of brackets and parenthesis.')",
"assert(editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi) && editor.match(/\\,\\s*?function\\s*?\\(\\s*?\\w*?\\s*?\\)\\s*?\\{/gi) && editor.match(/\\s*?\\}\\s*?\\)\\s*?\\;/gi).length === editor.match(/\\s*?function\\s*?\\(\\s*?\\w*?\\s*?\\)\\s*?\\{/gi).length, 'Each callback function should have a closing set of brackets and parenthesis.')",
"assert(editor.match(/\\$\\s*?\\.\\s*?getJSON\\s*?\\(\\s*?\"\\\/json\\\/cats\\.json\\?callback\\=\"\\s*?\\,\\s*?function\\s*?\\(\\s*?json\\s*?\\)\\s*?\\{/gi), 'You should be making use of the getJSON method given in the description to load data from the json file.')",
"assert(editor.match(/\\$\\s*?\\(\\s*?\\\"\\.message\\\"\\s*?\\)\\s*?\\.\\s*?html\\s*?\\(\\s*?JSON\\s*?\\.\\s*?stringify\\s*?\\(\\s*?json\\s*?\\)\\s*?\\)/gi), 'Don\\'t forget to make the <code>.html</code> change the contents of the message box so that it contains the result of the getJSON.')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" ",
" $(\"#getMessage\").on(\"click\", function(){",
" // Only change code below this line.",
"",
"",
"",
" // Only change code above this line.",
" });",
" ",
" });",
"fcces",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here",
" </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bb000000000000000000003",
"title": "Convert JSON Data to HTML",
"description": [
"Now that we're getting data from a JSON API, let's display it in our HTML.",
"We can use the <code>.map()</code> method to loop through our data and modify our HTML elements.",
"First, let's declare an html variable with <code>var html = \"\";</code>.",
"Then, let's loop through our JSON, adding more HTML to that variable. When the loop is finished, we'll render it.",
"Here's the code that does this:",
"<code>json.map(function(val) {</code>",
"<code>&thinsp;&thinsp;html = html + \"&lt;div class = 'cat'&gt;\"</code>",
"<code>&thinsp;&thinsp;for(var key in val) {</code>",
"<code>&thinsp;&thinsp;&thinsp;&thinsp;html = html + '&lt;div class = \"' + key + '\"&gt;' + val[key] + '&lt;/div&gt;';</code>",
"<code>&thinsp;&thinsp;}</code>",
"<code>&thinsp;&thinsp;html = html + \"&lt;/div&gt;&lt;br/&gt;\"</code>",
"<code>});</code>"
],
"tests": [
"assert(editor.match(/json\\.map/gi), 'The message box should have something in it.')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
"",
" $(\"#getMessage\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json?callback=\", function( json ) {",
"",
" // Only change code below this line.",
"",
"",
"",
"",
"",
"",
"",
"",
"",
" // Only change code above this line.",
"",
" $(\".message\").html(html);",
"",
" });",
" });",
" });",
"fcces",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here"," </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bb000000000000000000004",
"title": "Render Images from Data Sources",
"description": [
"In the JSON that we receive from Free Code Camp's Cat Photo API, each object has an attribute called \"imageLink\".",
"When we're looping through these objects, let's check whether an object attribute (key) is <code>imageLink</code>. If it is, instead of outputing the image link, let's render the image.",
"Here's the code that does this:",
"<code>if(key === \"imageLink\") {</code>",
"<code>&thinsp;&thinsp;html = html + '&lt;img class = \"' + key + '\"src = \"' + val[key] + '\"&gt;';</code>",
"<code>} else {</code>",
"<code>&thinsp;&thinsp;html = html + '&lt;div class = \"' + key + '\"&gt;' + val[key] + '&lt;/div&gt;';</code>",
"<code>}</code>"
],
"tests": [
"assert(editor.match(/imageLink/gi), 'You should have accessed the imageLink of each cat object.')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
"",
" $(\"#getMessage\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json?callback=\", function( json ) {",
"",
" var html = \"\";",
"",
" json.map(function(val) {",
"",
" html = html + \"<div class = 'cat'>\"",
"",
" for (var key in val) {",
"",
" // Only change code below this line.",
"",
"",
"",
" // Only change code above this line.",
"",
" }",
"",
" html = html + \"</div>\"",
"",
" });",
"",
" $(\".message\").html(html);",
"",
" });",
" });",
" });",
"fcces",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here",
" </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bb000000000000000000005",
"title": "Prefilter JSON",
"description": [
"If we don't want to render every cat photo we get from our Free Code Camp's Cat Photo JSON API, we can pre-filter the json before we loop through it.",
"Let's filter out the cat who's \"id\" key has a value of 1.",
"Here's the code to do this:",
"<code>json = json.filter(function(val) {</code>",
"<code>&thinsp;&thinsp;return(val.id !== 1);</code>",
"<code>});</code>"
],
"tests": [
"assert(editor.match(/filter/gi), 'You should be making use of the .filter method.')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
"",
" $(\"#getMessage\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json?callback=\", function( json ) {",
"",
" var html = \"\";",
"",
" json.map(function(val){",
"",
" val = \"<img src = '\" + val.imageLink + \"'/>\"",
"",
" html = html + \"<div class = 'cat'>\"",
"",
" // Only change code below this line.",
"",
"",
"",
" // Only change code above this line.",
"",
" for(var key in val){",
"",
" html = html + '<div class = \"' + key + '\">' + val[key] + '</div>';",
"",
" }",
"",
" html = html + \"</div>\"",
"",
" });",
"",
" $(\".message\").html(html);",
"",
" });",
" });",
" });",
"fcces",
"",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well message\">",
" The message will go here",
" </div>",
" </div>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>",
""
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bb000000000000000000006",
"title": "Get Geo-location Data",
"description": [
"Another cool thing we can do is access our user's current location. Every browser has a built in navigator that can give us this information.",
"The navigator will get our user's current longitude and latitude.",
"Here's some code that does this:",
"<code>if (navigator.geolocation) {</code>",
"<code>&thinsp;&thinsp;navigator.geolocation.getCurrentPosition(function(position) {</code>",
"<code>&thinsp;&thinsp;&thinsp;&thinsp;$(\"#data\").html(\"latitiude\" + position.coords.latitude + \"longitude\" + position.coords.longitude);</code>",
"<code>&thinsp;&thinsp;});</code>",
"<code>}</code>"
],
"tests": [
"assert(editor.match(/navigator\\.geolocation\\.getCurrentPosition/gi), 'You should make use of the <code>navigator.geolocation</code> to access the users current location.')"
],
"challengeSeed": [
"fccss",
" // Only change code below this line.",
"",
"",
"",
" // Only change code above this line.",
"fcces",
"<div id = \"data\">",
" <h4>You are here:</h4>",
" ",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
}
]
}

View File

@ -1,21 +1,21 @@
{
"name": "MongoDB",
"order" : 0.018,
"order" : 19,
"time": "3h",
"challenges": [
{
"id": "bd7243d8c341eddeaeb5bd0f",
"title": "Store Data in MongoDB",
"difficulty": 0.01,
"challengeSeed": ["133316035"],
"description": [
"We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.",
"If you don't already have Cloud 9 account, create one now at <a href='http://c9.io' target='_blank'>http://c9.io</a>.",
"Open up <a href='http://c9.io' target='_blank'>http://c9.io</a> and sign in to your account.",
"Click on Create New Workspace at the top right of the c9.io page, then click on the \"Create a new workspace\" popup that appears below it the button after you click on it.",
"Give your workspace a name.",
"Click on the \"+\" icon at the top right of the c9.io page to create a new workspace.",
"Give your workspace a name and an optional description.",
"Choose Node.js in the selection area below the name field.",
"Click the Create button. Then click into your new workspace.",
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
"Click the \"Create workspace\" button.",
"Once C9 builds and loads your workspace, you should see a terminal window in the lower right hand corner. In this window use the following commands. You don't need to know what these mean at this point.",
"Install <code>learnyoumongo</code> with this command: <code>npm install learnyoumongo -g</code>",
"Now start the tutorial by running <code>learnyoumongo</code>.",
"Whenever you run a command that includes <code>mongod</code> on c9.io, be sure to also use the <code>--nojournal</code> flag, like this: <code>mongod --nojournal</code>.",
@ -25,7 +25,7 @@
"Complete \"Mongod\"",
"Complete \"Connect\"",
"Complete \"Find\"",
"Complete \"Find Limit\"",
"Complete \"Find Project\"",
"Complete \"Insert\"",
"Complete \"Update\"",
"Complete \"Remove\"",

View File

@ -1,11 +1,11 @@
{
"name": "Node.js and Express.js",
"order" : 0.017,
"order" : 18,
"time": "20h",
"challenges": [
{
"id": "bd7153d8c441eddfaeb5bd0f",
"title": "Manage Packages with NPM",
"difficulty": 0.39,
"challengeSeed": ["126433450"],
"description": [
"We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.",
@ -34,13 +34,7 @@
"Complete \"Publish\"",
"Complete \"Version\"",
"Complete \"Publish Again\"",
"Complete \"Dist Tag\"",
"Complete \"Dist Tag Removal\"",
"Complete \"Outdated\"",
"Complete \"Update\"",
"Complete \"RM\"",
"Complete \"Finale\"",
"Once you've completed these steps, move on to our next challenge."
"Note Once you've completed these steps, you can skip the rest (which are currently buggy) and move on to our next challenge."
],
"type": "waypoint",
"challengeType": 2,
@ -59,17 +53,16 @@
{
"id": "bd7153d8c441eddfaeb5bdff",
"title": "Start a Node.js Server",
"difficulty": 0.40,
"challengeSeed": ["126411561"],
"description": [
"We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud. We'll do the first 7 steps of Node School's LearnYouNode challenges.",
"If you don't already have Cloud 9 account, create one now at <a href='http://c9.io' target='_blank'>http://c9.io</a>.",
"Open up <a href='http://c9.io' target='_blank'>http://c9.io</a> and sign in to your account.",
"Click on Create New Workspace at the top right of the c9.io page, then click on the \"Create a new workspace\" popup that appears below it the button after you click on it.",
"Give your workspace a name.",
"Click on the \"+\" icon at the top right of the c9.io page to create a new workspace.",
"Give your workspace a name and an optional description.",
"Choose Node.js in the selection area below the name field.",
"Click the Create button. Then click into your new workspace.",
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
"Click the \"Create workspace\" button.",
"Once C9 builds and loads your workspace, you should see a terminal window in the lower right hand corner. In this window use the following commands. You don't need to know what these mean at this point.",
"Run this command: <code>sudo npm install -g learnyounode</code>",
"Now start this tutorial by running <code>learnyounode</code>",
"Note that you can resize the c9.io's windows by dragging their borders.",
@ -101,12 +94,11 @@
{
"id": "bd7153d8c441eddfaeb5bdfe",
"title": "Continue working with Node.js Servers",
"difficulty": 0.41,
"challengeSeed": ["128836506"],
"description": [
"Let's continue the LearnYouNode Node School challenge. For this Waypoint, we'll do challenges 8 through 10.",
"Make sure that you are always in your project's \"workspace\" directory. You can always navigate back to this directory by running this command: <code>cd ~/workspace</code>.",
"Return to the c9.io workspace you created Now start this tutorial by running <code>learnyounode</code>",
"Return to the c9.io workspace you created. Now start this tutorial by running <code>learnyounode</code>",
"You can view this Node School module's source code on GitHub at <a href='https://github.com/workshopper/learnyounode'>https://github.com/workshopper/learnyounode</a>.",
"Complete \"HTTP Collect\"",
"Complete \"Juggling Async\"",
@ -130,7 +122,6 @@
{
"id": "bd7153d8c441eddfaeb5bdfd",
"title": "Finish working with Node.js Servers",
"difficulty": 0.42,
"challengeSeed": ["128836507"],
"description": [
"Let's continue the LearnYouNode Node School challenge. For this Waypoint, we'll do challenges 11 through 13.",
@ -159,7 +150,6 @@
{
"id": "bd7153d8c441eddfaeb5bd1f",
"title": "Build Web Apps with Express.js",
"difficulty": 0.43,
"challengeSeed": [
"126411559"
],
@ -167,21 +157,23 @@
"We'll build this Waypoint on Cloud 9, a powerful online code editor with a full Ubuntu Linux workspace, all running in the cloud.",
"If you don't already have Cloud 9 account, create one now at <a href='http://c9.io' target='_blank'>http://c9.io</a>.",
"Open up <a href='http://c9.io' target='_blank'>http://c9.io</a> and sign in to your account.",
"Click on Create New Workspace at the top right of the c9.io page, then click on the \"Create a new workspace\" popup that appears below it the button after you click on it.",
"Give your workspace a name.",
"Click on the \"+\" icon at the top right of the c9.io page to create a new workspace.",
"Give your workspace a name and an optional description.",
"Choose Node.js in the selection area below the name field.",
"Click the Create button. Then click into your new workspace.",
"In the lower right hand corner you should see a terminal window. In this window use the following commands. You don't need to know what these mean at this point.",
"Click the \"Create workspace\" button.",
"Once C9 builds and loads your workspace, you should see a terminal window in the lower right hand corner. In this window use the following commands. You don't need to know what these mean at this point.",
"Run this command: <code>git clone http://github.com/reddock/fcc_express && chmod 744 fcc_express/setup.sh && fcc_express/setup.sh && source ~/.profile</code>",
"Now start this tutorial by running <code>expressworks</code>",
"Note that you can resize the c9.io's windows by dragging their borders.",
"Make sure that you are always in your project's \"workspace\" directory. You can always navigate back to this directory by running this command: <code>cd ~/workspace</code>.",
"You can view this Node School module's source code on GitHub at <a href='https://github.com/azat-co/expressworks'>https://github.com/azat-co/expressworks</a>.",
"Complete \"Hello World\"",
"Complete \"Hello World!\"",
"Complete \"Static\"",
"Complete \"Jade\"",
"Complete \"Good Old Form\"",
"Complete \"Stylish CSS\"",
"Complete \"Session and Cookie\"",
"Complete \"Param Pam Pam\"",
"Complete \"What's In Query\"",
"Complete \"JSON Me\"",
"Once you've completed these steps, move on to our next challenge."
],

View File

@ -1,6 +1,7 @@
{
"name": "Object Oriented and Functional Programming",
"order": 0.010,
"order": 7,
"time": "1h",
"note": [
"Methods",
"Closures",
@ -14,32 +15,30 @@
{
"id":"cf1111c1c15feddfaeb1bdef",
"title": "Declare JavaScript Objects as Variables",
"difficulty":0,
"description":[
"Before we dive into Object Oriented Programming, let's revisit JavaScript objects.",
"Give your <code>motorBike</code> object a <code>wheels</code>, <code>engines</code> and <code>seats</code> attribute and set them to numbers."
],
"tests":[
"assert(typeof(motorBike.engines) === 'number', '<code>engines</code> should be have a <code>engines</code> attribute set to a number.');",
"assert(typeof(motorBike.wheels) === 'number', '<code>wheels</code> should be have a <code>engines</code> attribute set to a number.');",
"assert(typeof(motorBike.seats) === 'number', '<code>seats</code> should be have a <code>engines</code> attribute set to a number.');"
"assert(typeof(motorBike.engines) === 'number', 'message: <code>motorBike</code> should have a <code>engines</code> attribute set to a number.');",
"assert(typeof(motorBike.wheels) === 'number', 'message: <code>motorBike</code> should have a <code>wheels</code> attribute set to a number.');",
"assert(typeof(motorBike.seats) === 'number', 'message: <code>motorBike</code> should have a <code>seats</code> attribute set to a number.');"
],
"challengeSeed":[
"//Here is a sample Object",
"var car = {",
" \"wheels\":4,",
" \"engines\":1,",
" \"seats\":5",
"};",
"",
"//Now Let's make a similar Object called motorBike",
"//Give it two wheels, one engine and one seat",
"var motorBike = {",
"",
" // Only change code below this line.",
"",
"",
"",
" // Only change code above this line.",
"",
"};",
"",
"(function() {return JSON.stringify(motorBike);})();"
@ -51,18 +50,23 @@
{
"id":"cf1111c1c15feddfaeb2bdef",
"title": "Construct JavaScript Objects with Functions",
"difficulty":0,
"description":[
"We are also able to create objects using <code>constructor</code> functions.",
"Give your <code>motorBike</code> object a <code>wheels</code>, <code>engines</code> and <code>seats</code> attribute and set them to numbers."
"Here's an example of a constructor function:",
"<code>var Car = function() {</code>",
"<code>&thinsp;&thinsp;this.wheels = 4;</code>",
"<code>&thinsp;&thinsp;this.engines = 1;</code>",
"<code>&thinsp;&thinsp;this.seats = 1;</code>",
"<code>};</code>",
"Give your <code>myMotorBike</code> object a <code>wheels</code>, <code>engines</code> and <code>seats</code> attribute and set them to numbers.",
"You may be confused by the <code>this</code> keyword here. Don't worry, we will get to that very soon."
],
"tests":[
"assert(typeof((new MotorBike()).engines) === 'number', '<code>engines</code> should be have a <code>engines</code> attribute set to a number.');",
"assert(typeof((new MotorBike()).wheels) === 'number', '<code>wheels</code> should be have a <code>engines</code> attribute set to a number.');",
"assert(typeof((new MotorBike()).seats) === 'number', '<code>seats</code> should be have a <code>engines</code> attribute set to a number.');"
"assert(typeof((new MotorBike()).engines) === 'number', 'message: <code>myMotorBike</code> should have a <code>engines</code> attribute set to a number.');",
"assert(typeof((new MotorBike()).wheels) === 'number', 'message: <code>myMotorBike</code> should have a <code>wheels</code> attribute set to a number.');",
"assert(typeof((new MotorBike()).seats) === 'number', 'message: <code>myMotorBike</code> should have a <code>seats</code> attribute set to a number.');"
],
"challengeSeed":[
"// Let's add the properties engines and seats to the car in the same way that the property wheels has been added below. They should both be numbers.",
"var Car = function() {",
" this.wheels = 4;",
" this.engines = 1;",
@ -72,6 +76,7 @@
"var myCar = new Car();",
"",
"// Only change code below this line.",
"",
"var MotorBike = function() {",
"",
"",
@ -79,6 +84,7 @@
"};",
"",
"var myMotorBike = new MotorBike();",
"",
"// Only change code above this line.",
"",
"(function() {return JSON.stringify(myMotorBike);})();"
@ -89,34 +95,40 @@
{
"id":"cf1111c1c15feddfaeb3bdef",
"title":"Make Object Properties Private",
"difficulty":0,
"description":[
"Objects have their own attributes, called <code>properties</code>, and their own functions, called <code>methods</code>.",
"In the previous challenge, we used the <code>this</code> keyword to reference <code>public properties</code> and <code>public methods</code> of the current object.",
"We can also create <code>private properties</code> and <code>private methods</code>, which aren't accessible from outside the object.",
"To do this, we omit the word <code>this</code> from the <code>property</code> or <code>method</code> declaration.",
"To do this, just declare properties or functions within the constructor.",
"Let's create an object with two functions. One attached as a property and one not.",
"See if you can keep <code>myBike.speed</code> and <code>myBike.addUnit</code> private, while making <code>myBike.getSpeed</code> publicly accessible."
],
"tests":[
"assert(typeof(myBike.getSpeed)!=='undefined' && typeof(myBike.getSpeed) === 'function', 'The method getSpeed of myBike should be accessible outside the object');",
"assert(typeof(myBike.speed) === 'undefined', '<code>myBike.speed</code> should remain undefined.');",
"assert(typeof(myBike.addUnit) === 'undefined', '<code>myBike.addUnit</code> should remain undefined.');"
"assert(typeof(myBike.getSpeed)!=='undefined' && typeof(myBike.getSpeed) === 'function', 'message: The method getSpeed of myBike should be accessible outside the object.');",
"assert(typeof(myBike.speed) === 'undefined', 'message: <code>myBike.speed</code> should be undefined.');",
"assert(typeof(myBike.addUnit) === 'undefined', 'message: <code>myBike.addUnit</code> should remain undefined.');"
],
"challengeSeed":[
"//Let's create an object with a two functions. One attached as a property and one not.",
"var Car = function() {",
" this.gear = 1;",
" // this is a private variable",
" var gear = 1;",
" // this is a private function (also known as a private method)",
" function addStyle(styleMe){",
" return 'The Current Gear Is: ' + styleMe;",
" }",
" // this is a public method",
" this.getGear = function() {",
" return addStyle(this.gear);",
" };",
"",
"};",
"",
"var Bike = function() {",
"",
" // Only change code below this line.",
"",
" this.speed = 100;",
"",
" function addUnit(value) {",
" return value + \"KM/H\";",
" }",
@ -128,10 +140,12 @@
"};",
"",
"// Only change code above this line.",
"",
"var myCar = new Car();",
"",
"var myBike = new Bike();",
"",
"if(myBike.hasOwnProperty('getSpeed')){(function() {return JSON.stringify(myBike.getSpeed());})();};"
"if(myBike.hasOwnProperty('getSpeed')){(function() {return JSON.stringify(myBike.getSpeed());})();}"
],
"challengeType":1,
"type": "waypoint"
@ -139,20 +153,20 @@
{
"id":"cf1111c1c15feddfaeb4bdef",
"title":"Make Instances of Objects with a Constructor Function",
"difficulty":0,
"description":[
"Sometimes you'll want to be able to easily create similar objects.",
"Sometimes you'll want to be able to easily create many copies of an objects that all share the same methods.",
"Objects have their own attributes, called <code>properties</code>, and their own functions, called <code>methods</code>.",
"A function that creates objects is called a <code>constructor</code>.",
"You can create <code>instances</code> of an object using a <code>constructor</code>.",
"A constructor is a function that creates instances of an object that share the same methods and properties",
"Each new <code>instance</code> of this object <code>inherits</code> all the <code>properties</code> and <code>methods</code> of your original object.",
"Then you can give the instance new properties."
"Once an <code>instance</code> has been created you can add <code>properties</code> to that <code>instance</code> individually.",
"Add an <code>engines</code> property with a number value to the <code>myCar</code> instance."
],
"tests":[
"assert((new Car()).wheels === 4, 'The property <code>wheels</code> should still be 4 like in the object constructor');",
"assert(typeof((new Car()).engines) === 'undefined', 'There should not be a property engine in the object constructor');",
"assert(myCar.wheels === 4, 'The property wheels of myCar should be four');",
"assert(typeof(myCar.engines) === 'number', 'The property engine of myCar should be a number');"
"assert((new Car()).wheels === 4, 'message: The property <code>wheels</code> should still be 4 in the object constructor.');",
"assert(typeof((new Car()).engines) === 'undefined', 'message: There should not be a property <code>engines</code> in the object constructor.');",
"assert(myCar.wheels === 4, 'message: The property <code>wheels</code> of myCar should equal 4.');",
"assert(typeof(myCar.engines) === 'number', 'message: The property <code>engines</code> of myCar should be a number.');"
],
"challengeSeed":[
"var Car = function() {",
@ -162,7 +176,6 @@
"// Only change code below this line.",
"var myCar = new Car();",
"",
"//Add the property \"engines\" to myCar, and make it a number.",
"",
"",
"// Only change code above this line.",
@ -174,29 +187,34 @@
{
"id":"cf1111c1c15feddfaeb7bdef",
"title":"Iterate over Arrays with .map",
"difficulty":0,
"description":[
"<code>array = array.map(function(val){</code>",
"<code>&thinsp;&thinsp;return val+1;</code>",
"The <code>map</code> method is a convenient way to iterate through arrays. Here's an example usage:",
"<code>var timesFour = array.map(function(val){</code>",
"<code>&thinsp;&thinsp;return val*4;</code>",
"<code>});</code>",
"",
"The map method is one of the easiest ways to iterate through an array or object there is. Let's use it now.",
"Use the map function to add 3 to every value in the variable <code>array</code>"
"The <code>map</code> method will iterate through every element of the array, creating a new array with values that have been modified by the callback function, and return it.",
"In our example the callback only uses the value of the array element (the <code>val</code> argument) but your callback can also include arguments for the <code>index</code> and <code>array</code> being acted on.",
"Use the map function to add 3 to every value in the variable <code>array</code>."
],
"tests":[
"assert.deepEqual(array, [4,5,6,7,8], 'You should have added three to each value in the array');",
"assert(editor.getValue().match(/\\.map\\(/gi), 'You should be making use of the map method');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\]/gi), 'You should only modify the array with .map');"
"assert.deepEqual(newArray, [4,5,6,7,8], 'message: You should add three to each value in the array.');",
"assert(editor.getValue().match(/\\.map\\s*\\(/gi), 'message: You should be making use of the <code>map</code> method.');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\]/gi), 'message: You should only modify the array with <code>map</code>.');"
],
"challengeSeed":[
"//Use map to add three to each value in the array",
"var array = [1,2,3,4,5];",
"var oldArray = [1,2,3,4,5];",
"",
"// Only change code below this line.",
"",
"",
"var newArray = oldArray;",
"",
"",
"",
"// Only change code above this line.",
"(function() {return array;})();"
"",
"(function() {return newArray;})();"
],
"challengeType":1,
"type": "waypoint"
@ -204,25 +222,32 @@
{
"id":"cf1111c1c15feddfaeb8bdef",
"title":"Condense arrays with .reduce",
"difficulty":0,
"description":[
"Reduce can be useful for condensing and array or numbers into one value.",
"The array method <code>reduce</code> is used to iterate through an array and condense it into one value.",
"To use <code>reduce</code> you pass in a callback whose arguments are an accumulator (in this case, <code>previousVal</code>) and the current value (<code>currentVal</code>).",
"<code>reduce</code> has an optional second argument which can be used to set the initial value of the accumulator. If no initial value is specified it will be the first array element and currentVal will start with the second array element.",
"Here is an example of <code>reduce</code> being used to subtract all the values of an array:",
"<code>var singleVal = array.reduce(function(previousVal, currentVal) {</code>",
"<code>&thinsp;&thinsp;return previousVal+currentVal;</code>",
"<code>});</code>"
"<code>&thinsp;&thinsp;return previousVal - currentVal;</code>",
"<code>}, 0);</code>",
"Use the <code>reduce</code> method to sum all the values in <code>array</code> and assign it to <code>singleVal</code>."
],
"tests":[
"assert(singleVal == 30, 'singleVal should have been set to the result of you reduce operation');",
"assert(editor.getValue().match(/\\.reduce\\(/gi), 'You should have made use of the reduce method');"
"assert(singleVal == 30, 'message: <code>singleVal</code> should be equal to the sum of all items in the <code>array</code> variable.');",
"assert(editor.getValue().match(/\\.reduce\\s*\\(/gi), 'message: You should have made use of the <code>reduce</code> method.');"
],
"challengeSeed":[
"var array = [4,5,6,7,8];",
"var singleVal = 0;",
"",
"",
"// Only change code below this line.",
"",
"var singleVal = array;",
"",
"",
"",
"// Only change code above this line.",
"",
"(function() {return singleVal;})();"
],
"challengeType":1,
@ -231,27 +256,32 @@
{
"id":"cf1111c1c15feddfaeb9bdef",
"title":"Filter Arrays with .filter",
"difficulty":0,
"description":[
"filter is a useful method that can filter out values that don't match a certain criteria",
"Let's remove all the values greater than five",
"The <code>filter</code> method is used to iterate through an array and filter out elements where a given condition is not true.",
"<code>filter</code> is passed a callback function which takes the current value (we've called that <code>val</code>) as an argument.",
"Any array element for which the callback returns true will be kept and elements that return false will be filtered out.",
"The following code is an example of using filter to remove array elements that are not even numbers:",
"Note: We omit the second and third arguments since we only need the value",
"<code>array = array.filter(function(val) {</code>",
"<code>&thinsp;&thinsp;return val<4;</code>",
"<code>});</code>"
"<code>&thinsp;&thinsp;return val % 2 === 0;</code>",
"<code>});</code>",
"Use <code>filter</code> to remove all elements from <code>array</code> that are greater than 5."
],
"tests":[
"assert.deepEqual(array, [1,2,3,4,5], 'You should have removed all the values from the array that are greater than five');",
"assert(editor.getValue().match(/array\\.filter\\(/gi), 'You should be using the filter method to remove the values from the array');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7\\,8\\,9\\,10\\]/gi), 'You should only be using .filter to modify the contents of the array');"
"assert.deepEqual(newArray, [1,2,3,4,5], 'message: You should have removed all the values from the array that are greater than 5.');",
"assert(editor.getValue().match(/array\\.filter\\s*\\(/gi), 'message: You should be using the <code>filter</code> method to remove the values from the array.');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7\\,8\\,9\\,10\\]/gi), 'message: You should only be using <code>filter</code> to modify the contents of the array.');"
],
"challengeSeed":[
"var array = [1,2,3,4,5,6,7,8,9,10];",
"var oldArray = [1,2,3,4,5,6,7,8,9,10];",
"",
"// Only change code below this line.",
"",
"",
"var newArray = oldArray;",
"",
"// Only change code above this line.",
"(function() {return array;})();"
"",
"(function() { return newArray; })();"
],
"challengeType":1,
"type": "waypoint"
@ -259,25 +289,31 @@
{
"id":"cf1111c1c16feddfaeb1bdef",
"title": "Sort Arrays with .sort",
"difficulty":0,
"description":[
"You can use the method sort to easily sort the values in the array alphabetically or numerically",
"<code>var array = [1,3,2];</code>",
"<code>array = array.sort();</code>",
"This will return <code>[1, 2, 3]</code>"
"You can use the method <code>sort</code> to easily sort the values in an array alphabetically or numerically.",
"Unlike the previous array methods we have been looking at, <code>sort</code> actually alters the array in place. However, it also returns this sorted array.",
"<code>sort</code> can be passed a compare function as a callback. If no compare function is passed in it will convert the values to strings and sort alphabetically.",
"Here is an example of using sort with a compare function that will sort the elements from smallest to largest number:",
"<code>var array = [1, 12, 21, 2];</code>",
"<code>array.sort(function(a, b) {</code>",
"<code>&thinsp;&thinsp;return a - b;</code>",
"<code>});</code>",
"Use <code>sort</code> to sort <code>array</code> from largest to smallest."
],
"tests":[
"assert.deepEqual(array, ['alpha', 'beta', 'charlie'], 'You should have sorted the array alphabetically');",
"assert(editor.getValue().match(/\\[\\'beta\\'\\,\\s\\'alpha\\'\\,\\s'charlie\\'\\];/gi), 'You should be sorting the array using sort');",
"assert(editor.getValue().match(/\\.sort\\(\\)/gi), 'You should have made use of the sort method');"
"assert.deepEqual(array, [21, 12, 2, 1], 'message: You should have sorted the array from largest to smallest.');",
"assert(editor.getValue().match(/\\[1,\\s*12,\\s*21,\\s*2\\];/gi), 'message: You should only be using <code>sort</code> to modify the array.');",
"assert(editor.getValue().match(/\\.sort\\s*\\(/g), 'message: You should have made use of the <code>sort</code> method.');"
],
"challengeSeed":[
"var array = ['beta', 'alpha', 'charlie'];",
"var array = [1, 12, 21, 2];",
"",
"// Only change code below this line.",
"",
"",
"array.sort();",
"",
"// Only change code above this line.",
"",
"(function() { return array; })();"
],
"challengeType":1,
@ -286,22 +322,25 @@
{
"id": "cf1111c1c16feddfaeb2bdef",
"title": "Reverse Arrays with .reverse",
"difficulty": 0,
"description": [
"You can use the <code>.reverse()</code> function to reverse the contents of an array."
"You can use the <code>reverse</code> method to reverse the elements of an array.",
"<code>reverse</code> is another array method that alters the array in place, but it also returns the reversed array.",
"Add a line of code that uses <code>reverse</code> to reverse the <code>array</code> variable."
],
"tests": [
"assert.deepEqual(array, [7,6,5,4,3,2,1], 'You should reverse the array');",
"assert(editor.getValue().match(/\\.reverse\\(\\)/gi), '');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7/gi), '');"
"assert.deepEqual(array, [7,6,5,4,3,2,1], 'message: You should reverse the array.');",
"assert(editor.getValue().match(/\\.reverse\\s*\\(\\)/gi), 'message: You should use the <code>reverse</code> method.');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\,4\\,5\\,6\\,7/gi), 'message: You should only be using <code>revserse</code> to modify <code>array</code>.');"
],
"challengeSeed": [
"var array = [1,2,3,4,5,6,7];",
"",
"// Only change code below this line.",
"",
"",
"",
"// Only change code above this line.",
"",
"(function() {return array;})();"
],
"challengeType": 1,
@ -310,26 +349,30 @@
{
"id": "cf1111c1c16feddfaeb3bdef",
"title": "Concatenate Strings with .concat",
"difficulty": 0,
"description": [
"<code>.concat()</code> can be used to merge the contents of two arrays into one.",
"<code>array = array.concat(otherArray);</code>"
"<code>concat</code> can be used to merge the contents of two arrays into one.",
"<code>concat</code> takes an array as an argument and returns a new array with the elements of this array concatenated onto the end.",
"Here is an example of <code>concat</code> being used to concatenate <code>otherArray</code> onto the end of <code>oldArray</code>:",
"<code>newArray = oldArray.concat(otherArray);</code>",
"Use <code>.concat()</code> to concatenate <code>concatMe</code> onto the end of <code>oldArray</code> and assign it to <code>newArray</code>."
],
"tests": [
"assert.deepEqual(array, [1,2,3,4,5,6], 'You should concat the two arrays together');",
"assert(editor.getValue().match(/\\.concat\\(/gi), 'You should be using the concat method to merge the two arrays');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\]/gi) && editor.getValue().match(/\\[4\\,5\\,6\\]/gi), 'You should only modify the two arrays without changing the origional ones');"
"assert.deepEqual(newArray, [1,2,3,4,5,6], 'message: You should concatenate the two arrays together.');",
"assert(editor.getValue().match(/\\.concat\\s*\\(/gi), 'message: You should be using the <code>concat</code> method to merge the two arrays.');",
"assert(editor.getValue().match(/\\[1\\,2\\,3\\]/gi) && editor.getValue().match(/\\[4\\,5\\,6\\]/gi), 'message: You should only be using <code>concat</code> to modify the arrays.');"
],
"challengeSeed": [
"var array = [1,2,3];",
"var oldArray = [1,2,3];",
"",
"var concatMe = [4,5,6];",
"",
"// Only change code below this line.",
"",
"",
"var newArray = oldArray;",
"",
"// Only change code above this line.",
"(function() {return array;})();"
"",
"(function() { return newArray; })();"
],
"challengeType": 1,
"type": "waypoint"
@ -337,23 +380,26 @@
{
"id":"cf1111c1c16feddfaeb4bdef",
"title":"Split Strings with .split",
"difficulty":0,
"description":[
"You can use the <code>.split()</code> method to split a string into an array.",
"split uses the argument you give to to split the string.",
"<code>array = string.split(' ');</code>"
"You can use the <code>split</code> method to split a string into an array.",
"<code>split</code> uses the argument you pass in as a delimiter to determine which points the string should be split at.",
"Here is an example of <code>split</code> being used to split an array at every <code>s</code> character:",
"<code>var array = string.split('s');</code>",
"Use <code>split</code> to create an array of words from <code>string</code> and assign it to <code>array</code>."
],
"tests":[
"assert(typeof(array) === 'object' && array.length === 5, 'You should have split the string by it\\'s spaces');",
"assert(/\\.split\\(/gi, 'You should have made use of the split method on the string');"
"assert(/\\.split\\(/gi, 'message: You should use the <code>split</code> method on the string.');",
"assert(typeof(array) === 'object' && array.length === 5, 'message: You should split the string by its spaces.');"
],
"challengeSeed":[
"var string = \"Split me into an array\";",
"",
"// Only change code below this line.",
"",
"var array = string;",
"",
"// Only change code above this line.",
"",
"(function() {return array;})();"
],
"challengeType":1,
@ -362,23 +408,28 @@
{
"id":"cf1111c1c16feddfaeb5bdef",
"title":"Join Strings with .join",
"difficulty":0,
"description":[
"We can use the <code>.join()</code> method to join each element in an array into a string separated by whatever delimiter you provide as an argument to the join operation.",
"<code>var joinMe = joinMe.join(\" \");</code>"
"We can use the <code>join</code> method to join each element of an array into a string separated by whatever delimiter you provide as an argument.",
"The following is an example of using <code>join</code> to join all of the elements of an array into a string with all the elements seperated by word `Na`:",
"<code>var joinMe = [\"Na \", \"Na \", \"Na \", \"Na \", \"Batman!\"];</code>",
"<code>var joinedString = joinMe.join(\"Na \");</code>",
"<code>console.log(joinedString);</code>",
"Use the <code>join</code> method to create a string from <code>joinMe</code> with spaces in between each element and assign it to <code>joinedString</code>."
],
"tests":[
"assert(typeof(joinMe) === 'string' && joinMe === \"Split me into an array\", 'You should have joined the arrays by it\\'s spaces');",
"assert(/\\.join\\(/gi, 'You should have made use of the join method on the array');"
"assert(typeof(joinedString) === 'string' && joinedString === \"Split me into an array\", 'message: You should join the elements of the array with spaces.');",
"assert(/\\.join\\(/gi, 'message: You should use of the <code>join</code> method on the array.');"
],
"challengeSeed":[
"var joinMe = [\"Split\",\"me\",\"into\",\"an\",\"array\"];",
"",
"// Only change code below this line.",
"",
"joinMe = joinMe;",
"var joinedString = joinMe;",
"",
"// Only change code above this line.",
"(function() {return joinMe;})();"
"",
"(function() {return joinedString;})();"
],
"challengeType":1,
"type": "waypoint"

View File

@ -1,11 +1,11 @@
{
"name": "Upper Intermediate Algorithm Scripting",
"order": 0.011,
"order": 13,
"time": "50h",
"challenges": [
{
"id": "a2f1d72d9b908d0bd72bb9f6",
"title": "Make a Person",
"difficulty": "3.01",
"description": [
"Fill in the object constructor with the methods specified in the tests.",
"Those methods are getFirstName(), getLastName(), getFullName(), setFirstName(first), setLastName(last), and setFullName(firstAndLast).",
@ -22,25 +22,26 @@
"bob.getFullName();"
],
"tests": [
"expect(Object.keys(bob).length).to.eql(6);",
"expect(bob instanceof Person).to.be.true;",
"expect(bob.firstName).to.be.undefined();",
"expect(bob.lastName).to.be.undefined();",
"expect(bob.getFirstName()).to.eql('Bob');",
"expect(bob.getLastName()).to.eql('Ross');",
"expect(bob.getFullName()).to.eql('Bob Ross');",
"bob.setFirstName('Happy');",
"expect(bob.getFirstName()).to.eql('Happy');",
"bob.setLastName('Trees');",
"expect(bob.getLastName()).to.eql('Trees');",
"bob.setFullName('George Carlin');",
"expect(bob.getFullName()).to.eql('George Carlin');",
"bob.setFullName('Bob Ross');"
"assert.deepEqual(Object.keys(bob).length, 6, 'message: <code>Object.keys(bob).length</code> should return 6.');",
"assert.deepEqual(bob instanceof Person, true, 'message: <code>bob instanceof Person</code> should return true.');",
"assert.deepEqual(bob.firstName, undefined, 'message: <code>bob.firstName</code> should return undefined.');",
"assert.deepEqual(bob.lastName, undefined, 'message: <code>bob.lastName</code> should return undefined.');",
"assert.deepEqual(bob.getFirstName(), 'Bob', 'message: <code>bob.getFirstName()</code> should return \"Bob\".');",
"assert.deepEqual(bob.getLastName(), 'Ross', 'message: <code>bob.getLastName()</code> should return \"Ross\".');",
"assert.deepEqual(bob.getFullName(), 'Bob Ross', 'message: <code>bob.getFullName()</code> should return \"Bob Ross\".');",
"assert.strictEqual((function () { bob.setFirstName(\"Haskell\"); return bob.getFullName(); })(), 'Haskell Ross', 'message: <code>bob.getFullName()</code> should return \"Haskell Ross\" after <code>bob.setFirstName(\"Haskell\")</code>.');",
"assert.strictEqual((function () { bob.setLastName(\"Curry\"); return bob.getFullName(); })(), 'Bob Curry', 'message: <code>bob.getFullName()</code> should return \"Bob Curry\" after <code>bob.setLastName(\"Curry\")</code>.');",
"assert.strictEqual((function () { bob.setFullName(\"Haskell Curry\"); return bob.getFullName(); })(), 'Haskell Curry', 'message: <code>bob.getFullName()</code> should return \"Haskell Curry\" after <code>bob.setFullName(\"Haskell Curry\")</code>.');",
"assert.strictEqual((function () { bob.setFullName(\"Haskell Curry\"); return bob.getFirstName(); })(), 'Haskell', 'message: <code>bob.getFirstName()</code> should return \"Haskell\" after <code>bob.setFullName(\"Haskell Curry\")</code>.');",
"assert.strictEqual((function () { bob.setFullName(\"Haskell Curry\"); return bob.getLastName(); })(), 'Curry', 'message: <code>bob.getLastName()</code> should return \"Curry\" after <code>bob.setFullName(\"Haskell Curry\")</code>.');"
],
"MDNlinks": [
"Closures",
"Details of the Object Model"
],
"solutions": [
"var Person = function(firstAndLast) {\n\n var firstName, lastName;\n\n function updateName(str) { \n firstName = str.split(\" \")[0];\n lastName = str.split(\" \")[1]; \n }\n\n updateName(firstAndLast);\n\n this.getFirstName = function(){\n return firstName;\n };\n \n this.getLastName = function(){\n return lastName;\n };\n \n this.getFullName = function(){\n return firstName + \" \" + lastName;\n };\n \n this.setFirstName = function(str){\n firstName = str;\n };\n \n\n this.setLastName = function(str){\n lastName = str;\n };\n \n this.setFullName = function(str){\n updateName(str);\n };\n};\n\nvar bob = new Person('Bob Ross');\nbob.getFullName();"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -58,7 +59,6 @@
"id": "af4afb223120f7348cdfc9fd",
"title": "Map the Debris",
"dashedName": "bonfire-map-the-debris",
"difficulty": "3.02",
"description": [
"Return a new array that transforms the element's average altitude into their orbital periods.",
"The array will contain objects in the format <code>{name: 'name', avgAlt: avgAlt}</code>.",
@ -77,12 +77,15 @@
"orbitalPeriod([{name : \"sputnik\", avgAlt : 35873.5553}]);"
],
"tests": [
"expect(orbitalPeriod([{name : \"sputnik\", avgAlt : 35873.5553}])).to.eqls([{name: \"sputnik\", orbitalPeriod: 86400}]);",
"expect(orbitalPeriod([{name: \"iss\", avgAlt: 413.6}, {name: \"hubble\", avgAlt: 556.7}, {name: \"moon\", avgAlt: 378632.553}])).to.eqls([{name : \"iss\", orbitalPeriod: 5557}, {name: \"hubble\", orbitalPeriod: 5734}, {name: \"moon\", orbitalPeriod: 2377399}]);"
"assert.deepEqual(orbitalPeriod([{name : \"sputnik\", avgAlt : 35873.5553}]), [{name: \"sputnik\", orbitalPeriod: 86400}], 'message: <code>orbitalPeriod([{name : \"sputnik\", avgAlt : 35873.5553}])</code> should return <code>[{name: \"sputnik\", orbitalPeriod: 86400}]</code>.');",
"assert.deepEqual(orbitalPeriod([{name: \"iss\", avgAlt: 413.6}, {name: \"hubble\", avgAlt: 556.7}, {name: \"moon\", avgAlt: 378632.553}]), [{name : \"iss\", orbitalPeriod: 5557}, {name: \"hubble\", orbitalPeriod: 5734}, {name: \"moon\", orbitalPeriod: 2377399}], 'message: <code>orbitalPeriod([{name: \"iss\", avgAlt: 413.6}, {name: \"hubble\", avgAlt: 556.7}, {name: \"moon\", avgAlt: 378632.553}])</code> should return <code>[{name : \"iss\", orbitalPeriod: 5557}, {name: \"hubble\", orbitalPeriod: 5734}, {name: \"moon\", orbitalPeriod: 2377399}]</code>.');"
],
"MDNlinks": [
"Math.pow()"
],
"solutions": [
"function orbitalPeriod(arr) {\n var GM = 398600.4418;\n var earthRadius = 6367.4447;\n var TAU = 2 * Math.PI; \n return arr.map(function(obj) {\n return {\n name: obj.name,\n orbitalPeriod: Math.round(TAU * Math.sqrt(Math.pow(obj.avgAlt+earthRadius, 3)/GM))\n };\n });\n}\n\norbitalPeriod([{name : \"sputkin\", avgAlt : 35873.5553}]);\n"
],
"type": "bonfire",
"challengeType": 5,
"nameCn": "",
@ -99,7 +102,6 @@
{
"id": "a3f503de51cfab748ff001aa",
"title": "Pairwise",
"difficulty": "3.03",
"description": [
"Return the sum of all indices of elements of 'arr' that can be paired with one other element to form a sum that equals the value in the second argument 'arg'. If multiple sums are possible, return the smallest sum. Once an element has been used, it cannot be reused to pair with another.",
"For example, pairwise([1, 4, 2, 3, 0, 5], 7) should return 11 because 4, 2, 3 and 5 can be paired with each other to equal 7.",
@ -114,16 +116,19 @@
"pairwise([1,4,2,3,0,5], 7);"
],
"tests": [
"expect(pairwise([1, 4, 2, 3, 0, 5], 7)).to.equal(11);",
"expect(pairwise([1, 3, 2, 4], 4)).to.equal(1);",
"expect(pairwise([1,1,1], 2)).to.equal(1);",
"expect(pairwise([0, 0, 0, 0, 1, 1], 1)).to.equal(10);",
"expect(pairwise([], 100)).to.equal(0);"
"assert.deepEqual(pairwise([1, 4, 2, 3, 0, 5], 7), 11, 'message: <code>pairwise([1, 4, 2, 3, 0, 5], 7)</code> should return 11.');",
"assert.deepEqual(pairwise([1, 3, 2, 4], 4), 1, 'message: <code>pairwise([1, 3, 2, 4], 4), 1</code> should return 1.');",
"assert.deepEqual(pairwise([1,1,1], 2), 1, 'message: <code>pairwise([1,1,1], 2)</code> should return 1.');",
"assert.deepEqual(pairwise([0, 0, 0, 0, 1, 1], 1), 10, 'message: <code>pairwise([0, 0, 0, 0, 1, 1], 1)</code> should return 10.');",
"assert.deepEqual(pairwise([], 100), 0, 'message: <code>pairwise([], 100)</code> should return 0.');"
],
"MDNlinks": [
"Array.reduce()"
],
"type": "bonfire",
"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"
],
"challengeType": 5,
"nameCn": "",
"descriptionCn": [],

View File

@ -1,54 +1,34 @@
/* eslint-disable no-process-exit */
require('babel/register');
require('dotenv').load();
var fs = require('fs'),
Rx = require('rx'),
_ = require('lodash'),
path = require('path'),
app = require('../server/server'),
nonprofits = require('./nonprofits.json'),
jobs = require('./jobs.json');
app = require('../server/server');
function getFilesFor(dir) {
return fs.readdirSync(path.join(__dirname, '/' + dir));
}
var Challenge = app.models.Challenge;
var Nonprofit = app.models.Nonprofit;
var Job = app.models.Job;
var counter = 0;
var challenges = getFilesFor('challenges');
// plus two accounts for nonprofits and jobs seed.
var numberToSave = challenges.length + 1;
var destroy = Rx.Observable.fromNodeCallback(Challenge.destroyAll, Challenge);
var create = Rx.Observable.fromNodeCallback(Challenge.create, Challenge);
function completionMonitor() {
// Increment counter
counter++;
// Exit if all challenges have been checked
if (counter >= numberToSave) {
process.exit(0);
}
// Log where in the seed order we're currently at
console.log('Call: ' + counter + '/' + numberToSave);
}
Challenge.destroyAll(function(err, info) {
if (err) {
throw err;
} else {
console.log('Deleted ', info);
}
challenges.forEach(function(file) {
destroy()
.flatMap(function() { return Rx.Observable.from(challenges); })
.flatMap(function(file) {
var challengeSpec = require('./challenges/' + file);
var order = challengeSpec.order;
var block = challengeSpec.name;
var isBeta = !!challengeSpec.isBeta;
console.log('parsed %s successfully', file);
// challenge file has no challenges...
if (challengeSpec.challenges.length === 0) {
console.log('file %s has no challenges', file);
completionMonitor();
return;
return Rx.Observable.just([{ block: 'empty ' + block }]);
}
var challenges = challengeSpec.challenges
@ -66,54 +46,21 @@ Challenge.destroyAll(function(err, info) {
challenge.order = order;
challenge.suborder = index + 1;
challenge.block = block;
challenge.isBeta = challenge.isBeta || isBeta;
challenge.time = challengeSpec.time;
return challenge;
});
Challenge.create(
challenges,
function(err) {
if (err) {
throw err;
} else {
console.log('Successfully parsed %s', file);
completionMonitor(err);
}
return create(challenges);
})
.subscribe(
function(challenges) {
console.log('%s successfully saved', challenges[0].block);
},
function(err) { throw err; },
function() {
console.log('challenge seed completed');
process.exit(0);
}
);
});
});
Nonprofit.destroyAll(function(err, info) {
if (err) {
console.error(err);
} else {
console.log('Deleted ', info);
}
Nonprofit.create(nonprofits, function(err, data) {
if (err) {
throw err;
} else {
console.log('Saved ', data);
}
completionMonitor(err);
console.log('nonprofits');
});
});
Job.destroyAll(function(err, info) {
if (err) {
throw err;
} else {
console.log('Deleted ', info);
}
Job.create(jobs, function(err, data) {
if (err) {
console.log('error: ', err);
} else {
console.log('Saved ', data);
}
console.log('jobs');
completionMonitor(err);
});
});

29
seed/nonprofits.js Normal file
View File

@ -0,0 +1,29 @@
/* eslint-disable no-process-exit */
require('babel/register');
require('dotenv').load();
var Rx = require('rx');
var app = require('../server/server');
var Nonprofits = app.models.Nonprofit;
var nonprofits = require('./nonprofits.json');
var destroy = Rx.Observable.fromNodeCallback(Nonprofits.destroyAll, Nonprofits);
var create = Rx.Observable.fromNodeCallback(Nonprofits.create, Nonprofits);
destroy()
.flatMap(function() {
if (!nonprofits) {
return Rx.Observable.throw(new Error('No nonprofits found'));
}
return create(nonprofits);
})
.subscribe(
function(nonprofits) {
console.log('successfully saved %d nonprofits', nonprofits.length);
},
function(err) { throw err; },
function() {
console.log('nonprofit seed completed');
process.exit(0);
}
);

View File

@ -1,6 +1,5 @@
[
{
"id": "bd7157d8c441cbafaeb5bdef",
"whatDoesNonprofitDo": "We help the many less-fortunate Jewish families in our community, by providing them with nutritious food and energy to grow, learn, work, and give them hope for a better and brighter future.",
"websiteLink": "http://chasdeikaduri.org/",
"name": "Chasdei Kaduri",
@ -13,14 +12,13 @@
"form"
],
"projectDescription": "Campers will create a system will integrate the food inventory, donor and delivery driver management systems as well as replace the current application system with a custom form solution. System will include a more streamlined operations management, with user printable lists of inventory, drivers, and deliveries.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54c7e02f2c173c37015b2f36/604x309/00580a0567a4b3afda29d52b09e7e829/rQQ6zwq31Uya8ie9QHC-MlvfXxqftm9UPPe524JUhmwSEaZjQ7oL7U1tVoHLUj-gVUwM-7uzBGFsAXD_A_cx_JyAZP4Td-GMBJ-AebJNRAQP0m0v253eKMkURp63aG4%3Ds0-d-e1-ft.png",
"imageUrl": "https://pbs.twimg.com/media/B3d6B8PIYAAa6QL.jpg",
"logoUrl": "http://i.imgur.com/zQiM0P8.png",
"imageUrl": "http://i.imgur.com/xeRdA87.jpg",
"estimatedHours": 300,
"currentStatus": "completed",
"moneySaved": 60000
},
{
"id": "bd7158d8c464cbafaeb4bdef",
"whatDoesNonprofitDo": "We connect simple technology with last mile communities to reduce poverty.",
"websiteLink": "http://kopernik.info/",
"name": "Kopernik",
@ -29,14 +27,13 @@
"other"
],
"projectDescription": "Campers will create a Chrome browser extension to preserve sales data from a form, and upload in batches as the internet connection allows.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54d29f1e4c726fd765fa87ef/54d29f6388812dd367a243ab/x/018d9d3be5439870c56cccba5b3aa8bf/kopernik-logo-global.png",
"imageUrl": "http://kopernik.info/sites/default/files/updates/Presenting_the_low_carbon_t.jpg",
"logoUrl": "http://i.imgur.com/xTqjIkC.png",
"imageUrl": "http://i.imgur.com/xBAUJSa.jpg",
"estimatedHours": 100,
"currentStatus": "completed",
"moneySaved": 20000
},
{
"id": "bd1326d9c245cbafaeb4bdef",
"whatDoesNonprofitDo": "We distribute biodegradable toothbrushes globally to children in need.",
"websiteLink": "http://www.operationbrush.org/",
"name": "Operation Brush",
@ -45,14 +42,13 @@
"website"
],
"projectDescription": "Campers will create a mobile responsive website for the organization, with donation capabilities.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54d9810307b159a4d9027aa2/54d981bfe5eb145560fbb769/x/cf7f318bfe4aee631b0d0eeef272225c/logo.png",
"imageUrl": "http://www.operationbrush.org/images/temp/hands1.png",
"logoUrl": "http://i.imgur.com/DEDhImE.png",
"imageUrl": "http://i.imgur.com/RuA9Rgy.jpg",
"estimatedHours": 100,
"currentStatus": "completed",
"moneySaved": 20000
},
{
"id": "bd1325d8c464cbafaeb5bdef",
"whatDoesNonprofitDo": "We are the largest roller derby league in the world with around 250 adults and 150 junior skater members plus 500+ volunteers.",
"websiteLink": "http://www.rosecityrollers.com/about/our-charities/",
"name": "Rose City Rollers",
@ -61,14 +57,13 @@
"community"
],
"projectDescription": "Campers will create a volunteer management system with multi-user access and reporting capabilities.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54c1daf2d72d8eb868910b60/54c1dd4ecffcb09fc52b68a1/x/a8148f08769b449217e433bab8f39ddd/RCR-color.jpg",
"imageUrl": "http://www.rosecityrollers.com/wp-content/uploads/2015/01/BZ7_5923-X3-675x375.jpg",
"logoUrl": "http://i.imgur.com/ZZAZSs4.jpg",
"imageUrl": "http://i.imgur.com/WKS4cZ8.jpg",
"estimatedHours": 200,
"currentStatus": "started",
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1325d8c464cbafaeb6bde1",
"whatDoesNonprofitDo": "We provide urgently needed pediatric heart surgery and follow-up care for indigent children from developing countries",
"websiteLink": "http://www.saveachildsheart.com/global/young-leadership-program/",
"name": "Save a Child's Heart",
@ -77,14 +72,13 @@
"website"
],
"projectDescription": "Campers will create a single page fundraising website. In exchange for a donation, a user can customize a graphical 'heart' in someone's name or anonymously. The page will display all of the hearts on a 'wall of hearts.'",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/548b36629137780091a973cc/666x666/6c7a366ffb659649f6377d4a431687cd/country-logos-1-300dpi.jpg",
"imageUrl": "http://www.saveachildsheart.com/wp-content/uploads/2013/10/7.2.5_Internation_Photograohy_Exhibition.jpg",
"logoUrl": "http://i.imgur.com/t6tpiEW.jpg",
"imageUrl": "http://i.imgur.com/xqhvdn2.jpg",
"estimatedHours": 200,
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1225d8c464cbafaeb4bdef",
"whatDoesNonprofitDo": "We empower youth with technology by providing age appropriate resources and education.",
"websiteLink": "http://savvycyberkids.org/",
"name": "Savvy Cyber Kids",
@ -93,14 +87,13 @@
"website"
],
"projectDescription": "Campers will create a website where potential donors can view which schools already have the Savvy Cyber Kids books, and donate books to those schools that do not.",
"logoUrl": "https://trello-attachments.s3.amazonaws.com/54ee3c7bf205562680177b59/218x190/1dc460de4edc9fdd4b481b24e93cfb23/logo.png",
"imageUrl": "http://www.privatewifi.com/wp-content/uploads/2014/10/Halpert.jpg",
"logoUrl": "http://i.imgur.com/JgxYVJ5.png",
"imageUrl": "http://i.imgur.com/ZTg12ao.jpg",
"estimatedHours": 200,
"currentStatus": "started",
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1325d8c464cbafaeb7bcef",
"whatDoesNonprofitDo": "We bring a new edge to arts and medicine in the Bay Area through powerful live performances of new music to those who feel marginalized by their affliction.",
"websiteLink": "http://transcendentpathways.org/",
"name": "Transcendent Pathways",
@ -109,14 +102,13 @@
"other"
],
"projectDescription": "Campers will build a website where medical facilities can list music therapy time slots, and musicians can sign up to fill these slots.",
"logoUrl": "http://static1.squarespace.com/static/521b8957e4b024f66a58b214/t/521b8e9de4b093a8696eb9b8/1398718364447/?format=750w",
"imageUrl": "https://trello-attachments.s3.amazonaws.com/54fdb0328917ca64e9e8a79f/54fdc3b710f67caf6da14719/x/49fbe0012179bf254928f3f2a44810b4/Screen_2BShot_2B2013-08-26_2Bat_2B1.32.35_2BPM.png",
"logoUrl": "http://i.imgur.com/JV4rcKX.png",
"imageUrl": "http://i.imgur.com/gyhrPee.jpg",
"estimatedHours": 200,
"currentStatus": "started",
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1325d8c464cbafaeb8bdef",
"whatDoesNonprofitDo": "We have provide volunteer matching fairs and silent art auctions at events across Canada. Rather than bid money on artwork, participants bid volunteer hours.",
"websiteLink": "http://www.timeraiser.ca/",
"name": "Timeraiser",
@ -125,14 +117,13 @@
"other"
],
"projectDescription": "Campers will build a mobile responsive web form to allow Timeraiser eventgoers to select which nonprofit organizations they're interested in volunteering with. System will have Salesforce integration and reporting capabilities.",
"logoUrl": "http://www.timeraiser.ca/uploads/5/6/1/4/5614163/1277176.png?480",
"imageUrl": "http://www.timeraiser.ca/uploads/5/6/1/4/5614163/______________4571248_orig.png",
"logoUrl": "http://i.imgur.com/USK8ld7.png",
"imageUrl": "http://i.imgur.com/7apWppe.jpg",
"estimatedHours": 200,
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1325d8c464cbafaeb7bdef",
"whatDoesNonprofitDo": "We focus on raising funds to assist injured homeless animals.",
"websiteLink": "http://www.peoplesavinganimals.org/",
"name": "People Saving Animals",
@ -143,14 +134,13 @@
"form"
],
"projectDescription": "Campers will build an adoption database and all related web interfaces and forms to allow animal shelters to easily post animals, photos, and relevant medical information. They'll make it easy for locals to browse these animals and adopt them. Once completed, this project will be translated into Spanish.",
"logoUrl": "https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xfa1/v/t1.0-9/59709_501505959886494_1605714757_n.jpg?oh=e12c08c046d824765a02242b7c8c3bb5&oe=560CFA6A",
"imageUrl": "https://scontent-sjc2-1.xx.fbcdn.net/hphotos-xta1/t31.0-8/11270516_844556088914811_757350153964826829_o.jpg",
"logoUrl": "http://i.imgur.com/iKcKcpg.jpg",
"imageUrl": "http://i.imgur.com/b9ZeU7R.jpg",
"estimatedHours": 300,
"currentStatus": "started",
"currentStatus": "completed",
"moneySaved": 60000
},
{
"id": "bd1325d8c464cbafaeb6bde2",
"whatDoesNonprofitDo": "We preserve Florida's health by regulating septic contractors and reviewing logs of sewage collection and disposal.",
"websiteLink": "http://www.floridahealth.gov/",
"name": "Florida Department of Health",
@ -161,14 +151,13 @@
"other"
],
"projectDescription": "Campers will build mobile responsive web forms to allow contractors to seamlessly log the chain of custody for potentially hazardous sewage. They'll also build a government-facing database that allows for easy monitoring and reporting of activity.",
"logoUrl": "http://www.floridahealth.gov/_new/_files/images/DOH_logo.png",
"imageUrl": "http://www.dep.state.fl.us/central/Home/Watershed/Home.jpg",
"logoUrl": "http://i.imgur.com/J3Scbsp.png",
"imageUrl": "http://i.imgur.com/8LEFrKy.jpg",
"estimatedHours": 200,
"currentStatus": "started",
"currentStatus": "completed",
"moneySaved": 40000
},
{
"id": "bd1325d8c464cbafaeb6bde3",
"whatDoesNonprofitDo": "We strengthen the value of songwriting and independent music in Columbus, Ohio.",
"websiteLink": "http://columbussongwritersassociation.com",
"name": "Columbus Songwriters Association",
@ -177,14 +166,13 @@
"website"
],
"projectDescription": "Build mobile responsive website that allows users to see browse our partners, their photos and information, and connect with them.",
"logoUrl": "https://columbussongwritersassociation.files.wordpress.com/2014/06/csa-logo.jpeg?w=705&h=435&crop=1",
"imageUrl": "https://columbussongwritersassociation.files.wordpress.com/2015/03/10502364_918551148225410_5082247612691070613_n.jpg?w=705&h=344&crop=1",
"logoUrl": "http://i.imgur.com/UN85TI4.jpg",
"imageUrl": "http://i.imgur.com/NFxL1oS.jpg",
"estimatedHours": 100,
"currentStatus": "completed",
"moneySaved": 20000
},
{
"id": "bd1325d8c464cbafaeb4bbb",
"whatDoesNonprofitDo": "We leverage all the benefits of cycling to support and improve the lives of youth and teens in the Triangle region.",
"websiteLink": "http://www.trianglebikeworks.org",
"name": "Triangle Bike Works",
@ -200,7 +188,6 @@
"moneySaved": 0
},
{
"id": "bd1325d8c464cbafaeb4bccc",
"whatDoesNonprofitDo": "We work to eradicate female genital mutilation in the US and Gambia. We work with survivors and communities.",
"websiteLink": "http://safehandsforgirls.org/",
"name": "Safe Hands for Girls",
@ -216,7 +203,6 @@
"moneySaved": 0
},
{
"id": "bd1325d8c464cbafaeb4beff",
"whatDoesNonprofitDo": "We're a part of the Department of Psychiatry at Mass General Hospital. We teach an innovative way for helping people that have challenging behaviors.",
"websiteLink": "http://www.thinkkids.org/",
"name": "Think Kids at Massachusetts General Hospital",
@ -225,14 +211,13 @@
"volunteer"
],
"projectDescription": "We would like help developing a simple online based portal for both our trainees and trainers where we can store and share documents, track their progress, and incorporate a blackboard/chat forum.",
"logoUrl": "http://www.thinkkids.org/wp-content/themes/think-kids/images/logo.png",
"logoUrl": "http://i.imgur.com/fu6dTmH.png",
"imageUrl": "http://i.imgur.com/hiGJms5.png",
"estimatedHours": 300,
"currentStatus": "open",
"currentStatus": "started",
"moneySaved": 0
},
{
"id": "bd1325d8c464cbaeaeb4bdef",
"whatDoesNonprofitDo": "We enable, educate, and empower students from rural backgrounds in Uttar Pradesh, India.",
"websiteLink": "http://www.milaan.in/",
"name": "Milaan",
@ -242,13 +227,12 @@
],
"projectDescription": "Campers will build a basic website for the US operations of Milaan. ",
"logoUrl": "http://i.imgur.com/GLq1qqD.png",
"imageUrl": "http://www.milaan.in/wp-content/uploads/2014/07/IMG_2624-e1432218749722.jpg",
"imageUrl": "http://i.imgur.com/PkMHQ8N.jpg",
"estimatedHours": 100,
"currentStatus": "open",
"moneySaved": 0
},
{
"id": "bd1325d8c464cbafaeb4beee",
"whatDoesNonprofitDo": "We're committed to closing the opportunity gap for children in Baltimore City by providing high quality after school and in-school programs.",
"websiteLink": "http://childfirstauthority.org/",
"name": "Child First Authority",
@ -258,58 +242,39 @@
],
"projectDescription": "Campers will build a dynamic database that will allow 7 community school coordinators to (1) input student-level absenteeism data, (2) code and track outreach efforts, (3) code root causes for absenteeism, and (4) track trends in each area. Currently, Child First uses an unwieldy excel spreadsheet to do this.",
"logoUrl": "http://i.imgur.com/YlPsQmN.jpg",
"imageUrl": "http://childfirstauthority.org/wp-content/uploads/2012/09/CFAHEADER7.gif",
"imageUrl": "http://i.imgur.com/Z2RfQku.gifv",
"estimatedHours": 200,
"currentStatus": "open",
"currentStatus": "started",
"moneySaved": 0
},
{
"id": "bd1325d8c464cbafaeb4bdef",
"whatDoesNonprofitDo": "SOLACE Foundation provides drug overdose prevention and awareness training as well as grief support for bereaved families.",
"websiteLink": "https://www.facebook.com/www.solaceorangecounty.org",
"name": "The Solace Foundation of Orange County",
"endUser": "Donors",
"approvedDeliverables": ["Website"],
"projectDescription": "Campers will build a basic website that accepts donations.",
"logoUrl": "http://i.imgur.com/79E3nP0.png",
"imageUrl": "http://i.imgur.com/kCWN1iT.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": 100
},
{
"id": "bd1325d8c463cbafaeb4bdef",
"whatDoesNonprofitDo": "We are an interdisciplinary team that works towards harmony among humans and nature through three distinct branches: sustainable agriculture, environmental education and applied and appropriate technology; focused in Líbano, Tolima, Colombia.",
"websiteLink": "string",
"websiteLink": "",
"name": "QET America",
"endUser": "Donors",
"approvedDeliverables": ["Website"],
"projectDescription": "Campers will build a multiple language website (English, Spanish) that accepts donations.",
"logoUrl": "http://i.imgur.com/jPuiPOy.jpg",
"imageUrl": "http://i.imgur.com/zaaL2pj.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": 100
"estimatedHours": 100,
"currentStatus": "open",
"moneySaved": 0
},
{
"id": "bd1325d8c462cbafaeb4bdef",
"whatDoesNonprofitDo": "1to1 Movement provides free environmental education in schools",
"websiteLink": "http://1to1movement.org/",
"stakeholderName": "string",
"stakeholderEmail": "string",
"name": "1 to 1 Movement",
"endUser": "Pledgers",
"approvedDeliverables": ["Web App"],
"projectDescription": "Campers will build a simple, social, data-driven application that allows people to see the impact of their actions. User can make a pledge and track the outcome. Will make use of the D3.js visualization library.",
"logoUrl": "http://i.imgur.com/jaqxg0O.png",
"imageUrl": "http://i.imgur.com/GXSWTZw.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": 300
"estimatedHours": 300,
"currentStatus": "open",
"moneySaved": 0
},
{
"id": "bd1325d8c464cbcfaeb4bdef",
"whatDoesNonprofitDo": "Our missions is to elevate the national dialogue and engage the American people around climate change policy and the promotion of real clean energy solutions in the United States.",
"websiteLink": "http://www.usclimateplan.org/",
"name": "US Climate Plan",
@ -318,24 +283,47 @@
"projectDescription": "Campers will build a basic website for sharing information, feeds from different campaigns websites.",
"logoUrl": "http://i.imgur.com/uAyUiMN.png",
"imageUrl": "http://i.imgur.com/2Og5tqy.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": 100
"estimatedHours": 100,
"currentStatus": "open",
"moneySaved": 0
},
{
"id": "bd1325d8c461cbafaeb4bdef",
"whatDoesNonprofitDo": "We empower the community through improved literacy.",
"websiteLink": "http://www.tleliteracy.com/",
"stakeholderName": "Darlene Brown",
"stakeholderEmail": "string",
"name": "The Learning Exchange",
"endUser": "string",
"endUser": "Community members",
"approvedDeliverables": ["Website"],
"projectDescription": "Campers will build a simple website to replace essentialskillsquebec.com. Site will host many documents related to the Nine Essential Skills.",
"logoUrl": "http://i.imgur.com/jXQY01H.png",
"imageUrl": "http://i.imgur.com/iUXBpeL.jpg",
"interestedCampers": [],
"confirmedCampers": [],
"estimatedHours": 100
"estimatedHours": 100,
"currentStatus": "started",
"moneySaved": 0
},
{
"whatDoesNonprofitDo": "Options Inc. is an organization that was founded in 1979 to assist adults with disabilities in living and working in the community. We provide transportation to approximately 230 individuals.",
"websiteLink": "www.options-inc.org",
"name": "Options Inc.",
"endUser": "Administrators and Persons with Disabilities",
"approvedDeliverables": ["Web App"],
"projectDescription": "Campers will build a system to store all of Options Inc.'s clients addresses, optimize routes for our 23 vehicles, and schedule their staff for these routes.",
"logoUrl": "http://i.imgur.com/jGWRMuF.jpg",
"imageUrl": "http://i.imgur.com/VUuJJlM.jpg",
"estimatedHours": 300,
"currentStatus": "open",
"moneySaved": 0
},
{
"whatDoesNonprofitDo": "Our goal is to improve addiction treatment and recovery services through targeted outreach, policy development, and direct support services for addicts, their families and health professionals.",
"websiteLink": "http://www.taadas.org/",
"name": "Tennessee Association of Alcohol Drug and other Addiction Services",
"endUser": "Administrators and Persons with Disabilities",
"approvedDeliverables": ["Website"],
"projectDescription": "Campers will build a modern, mobile-responsive website.",
"logoUrl": "http://i.imgur.com/kYHgY0F.jpg",
"imageUrl": "http://i.imgur.com/W6L1sGV.jpg",
"estimatedHours": 100,
"currentStatus": "open",
"moneySaved": 0
}
]

View File

@ -1,527 +0,0 @@
{
"name": "JSON APIs and Ajax",
"order": 0.0065,
"challenges": [
{
"id": "bad87fed1348bd9aeca08826",
"title": "Trigger on click Events with jQuery",
"difficulty": 3.19,
"description": [
"<code>$(\"#getMessage\").on(\"click\", function(){</code>",
"<code>&thinsp;&thinsp;$(\".message\").html(\"Here is the message\");</code>",
"<code>});</code>"
],
"tests": [
"assert(editor.match(/\\$\\(\\s?\\\"\\#getMessage\\\"\\s?\\)\\.on\\s?\\(\\s?\\\"click\\\"\\,\\s?function\\s?\\(\\)\\s?\\{/gi), 'You should have bound the click event to the getMessage button')",
"assert(editor.match(/\\$\\(\\s?\\\"\\.message\\\"\\s?\\)\\.html\\(\\s?\\\"Here\\sis\\sthe\\smessage\\\"\\s?\\);/gi), 'You should set te value of the #message box to be the message given in the description')",
"assert(editor.match(/\\}\\);/gi) && editor.match(/\\}\\);/gi).length >= 2, 'Make sure that you close off all of your functions')"
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" ",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <br/>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well Message\">",
" The message will go here",
" </div>",
" </div>",
" <br/>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad87fee1348bd9aeca08826",
"title": "Learn how JSON works",
"difficulty": 3.19,
"description": [
"JSON stands for \"JavaScript Object Notation\". It\"s how you create objects in JavaScript.",
"JSON is a series of \"key-value pairs\". Everything on the left of the colon (<code>:</code>) is the \"key\" you use to unlock the \"value\" on the right of the colon."
],
"tests": [
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"#getMessage\").on(\"click\", function(){",
" $(\".message\").html(\"Here is the message\");",
" });",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class = \"row text-center\">",
" <h2>Cat Photo Finder</h2>",
" </div>",
" <br/>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12 well Message\">",
" The message will go here",
" </div>",
" </div>",
" <br/>",
" <div class = \"row text-center\">",
" <div class = \"col-xs-12\">",
" <button id = \"getMessage\" class = \"btn btn-primary\">",
" Get Message",
" </button>",
" </div>",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad84fee1348bd9aecc48826",
"title": "Read Data from an Element Using jQuery",
"dashedName": "waypoint-read-data-from-an-element-using-jquery",
"difficulty": 3.17,
"description": [
"Let's make everything roll with <code>rollOut</code>."
],
"tests": [
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"button\").on(\"click\", function() {",
" $(\"#click-me\").addClass(\"animated shake\");",
" });",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class=\"row\">",
" <div class=\"col-xs-2\">",
" <input type=\"checkbox\" id=\"check-me\">",
" </div>",
" <div class=\"col-xs-10\">",
" <p>#check-me</p>",
" </div>",
" <button class=\"btn btn-block btn-primary\">#click-me</button>",
" <span>Is the checkbox checked?</span>",
" <span id=\"checked-state\"></span>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad84fee1348bd9aecc38826",
"title": "Read Data from an Element Using jQuery",
"dashedName": "waypoint-read-data-from-an-element-using-jquery",
"difficulty": 3.17,
"description": [
"Let's make everything roll with <code>rollOut</code>."
],
"tests": [
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"button\").on(\"click\", function() {",
" $(\"#click-me\").addClass(\"animated shake\");",
" $(\"#checked-state\").text(\"happy text\");",
" });",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class=\"row\">",
" <div class=\"col-xs-2\">",
" <input type=\"checkbox\" id=\"check-me\">",
" </div>",
" <div class=\"col-xs-10\">",
" <p>#check-me</p>",
" </div>",
" <button class=\"btn btn-block btn-primary\">#click-me</button>",
" <span>Is the checkbox checked?</span>",
" <span id=\"checked-state\"></span>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad84fee1348bd9aecc28826",
"title": "Read Data from an Element Using jQuery",
"dashedName": "waypoint-read-data-from-an-element-using-jquery",
"difficulty": 3.17,
"description": [
"Let's make everything roll with <code>rollOut</code>."
],
"tests": [
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"button\").on(\"click\", function() {",
" $(\"#click-me\").addClass(\"animated shake\");",
" $(\"#checked-state\").text($(\"#check-me\").prop(\"checked\"));",
" });",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class=\"row\">",
" <div class=\"col-xs-2\">",
" <input type=\"checkbox\" id=\"check-me\">",
" </div>",
" <div class=\"col-xs-10\">",
" <p>#check-me</p>",
" </div>",
" <button class=\"btn btn-block btn-primary\">#click-me</button>",
" <span>Is the checkbox checked?</span>",
" <span id=\"checked-state\"></span>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad84fee1348bd9aecc18826",
"title": "Read Data from an Element Using jQuery",
"dashedName": "waypoint-read-data-from-an-element-using-jquery",
"difficulty": 3.17,
"description": [
],
"tests": [
],
"challengeSeed": [
"fccss",
" $(document).ready(function() {",
" $(\"button\").on(\"click\", function() {",
" $(\"#click-me\").addClass(\"animated shake\");",
" $(\"#checked-state\").text($(\"#check-me\").prop(\"checked\"));",
" });",
" });",
"fcces",
"",
"<!-- You shouldn't need to modify code below this line -->",
"",
"<div class=\"container-fluid\">",
" <div class=\"row\">",
" <div class=\"col-xs-2\">",
" <input type=\"checkbox\" id=\"check-me\">",
" </div>",
" <div class=\"col-xs-10\">",
" <p>#check-me</p>",
" </div>",
" <button class=\"btn btn-block btn-primary\">#click-me</button>",
" <span>Is the checkbox checked?</span>",
" <span id=\"checked-state\"></span>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad87fee1348bd9aecc08826",
"title": "Trigger onHover Events with jQuery",
"dashedName": "waypoint-trigger-onhover-events-with-jquery",
"difficulty": 3.18,
"description": [
],
"tests": [
],
"challengeSeed": [
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad87fee1348bd9aebc08726",
"title": "Learn how JSON Works",
"description": [
"JSON stands for \"JavaScript Object Notation\". It\"s how you create objects in JavaScript.",
"JSON is a series of \"key-value pairs\". Everything on the left of the colon (<code>:</code>) is the \"key\" you use to unlock the \"value\" on the right of the colon."
],
"tests": [
],
"challengeSeed": [
"[",
" {",
" \"id\": 0,",
" \"imageLink\": \"http://rs611.pbsrc.com/albums/tt194/allypopper423/Funny-Cat-Green-Avacado.jpg~c200\",",
" \"codeNames\": [",
" \"Juggernaut\",",
" \"Mrs. Wallace\",",
" \"Buttercup\"",
" ]",
" },",
" {",
" \"id\": 1,",
" \"imageLink\": \"http://cdn.grumpycats.com/wp-content/uploads/2012/09/GC-Gravatar-copy.png\",",
" \"codeNames\": [",
" \"Oscar\",",
" \"Scrooge\",",
" \"Tyrion\"",
" ]",
" },",
" {",
" \"id\": 2,",
" \"imageLink\": \"http://www.kittenspet.com/wp-content/uploads/2012/08/cat_with_funny_face_3-200x200.jpg\",",
" \"codeNames\": [",
" \"The Doctor\",",
" \"Loki\",",
" \"Joker\"",
" ]",
" }",
"]"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad87fee1348bd9aebc08826",
"title": "Get Data from an URL Using jQuery",
"dashedName": "waypoint-get-data-from-a-url-using-jquery",
"difficulty": 3.21,
"description": [
],
"tests": [
],
"challengeSeed": [
"fccss",
"",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
"",
" });",
" });",
"",
" });",
"fcces",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad87fee1348bd9ae9c08826",
"title": "Loop through JSON Data Using jQuery",
"dashedName": "waypoint-loop-through-json-data-using-jquery",
"difficulty": 3.22,
"description": [
],
"tests": [
],
"challengeSeed": [
"fccss",
"",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
"",
" });",
" });",
"",
" });",
"fcces",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad88fee1348bd9ae8c08726",
"title": "Wire AJAX Call into a jQuery Click Event",
"dashedName": "waypoint-wire-ajax-call-into-a-jquery-click-event",
"difficulty": 3.24,
"description": [
"<img src=\"https://www.evernote.com/l/AjmAQ5BxGrFGRrWl_j2eSpGZMfrunfse89gB/image.png\">"
],
"tests": [
],
"challengeSeed": [
"fccss",
" var random = function() { return Math.floor(Math.random() * 3) }",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
"",
" });",
" });",
"",
" });",
"fcces",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad88fee1348bd9ae8c08626",
"title": "Wire AJAX Call into a jQuery Click Event",
"dashedName": "waypoint-wire-ajax-call-into-a-jquery-click-event",
"difficulty": 3.24,
"description": [
"<img src=\"https://www.evernote.com/l/AjmAQ5BxGrFGRrWl_j2eSpGZMfrunfse89gB/image.png\">"
],
"tests": [
],
"challengeSeed": [
"fccss",
" var random = function() { return Math.floor(Math.random() * 3) }",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
" var kitten = json[random()];",
" });",
" });",
"",
" });",
"fcces",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad88fee1348bd9ae8c08526",
"title": "Wire AJAX Call into a jQuery Click Event",
"dashedName": "waypoint-wire-ajax-call-into-a-jquery-click-event",
"difficulty": 3.24,
"description": [
"<img src=\"https://www.evernote.com/l/AjmAQ5BxGrFGRrWl_j2eSpGZMfrunfse89gB/image.png\">"
],
"tests": [
],
"challengeSeed": [
"fccss",
" var random = function() { return Math.floor(Math.random() * 3) }",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
" var kitten = json[random()];",
" $(\"<img src=\"\" + kitten.imageLink + \"\">\").appendTo(\"#output\");",
" });",
" });",
"",
" });",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
},
{
"id": "bad88fee1348bd9ae8c08426",
"title": "Wire AJAX Call into a jQuery Click Event",
"dashedName": "waypoint-wire-ajax-call-into-a-jquery-click-event",
"difficulty": 3.24,
"description": [
"<img src=\"https://www.evernote.com/l/AjmAQ5BxGrFGRrWl_j2eSpGZMfrunfse89gB/image.png\">"
],
"tests": [
],
"challengeSeed": [
"fccss",
" var random = function() { return Math.floor(Math.random() * 3) }",
" $(document).ready(function() {",
"",
" $(\"#cat-button\").on(\"click\", function() {",
" $.getJSON(\"/json/cats.json\", function( json ) {",
" var kitten = json[random()];",
" $(\"<img src=\"\" + kitten.imageLink + \"\">\").appendTo(\"#output\");",
" $(\"<h3>Code name: \" + kitten.codeNames[random()] + \"</h3>\").appendTo(\"#output\");",
" });",
" });",
"",
" });",
"fcces",
"<div class=\"container-fluid\">",
" <button id=\"cat-button\" class=\"btn btn-primary btn-block btn-lg\">#cat-button</button>",
" <div class=\"jumbotron\" id=\"output\">",
" </div>",
"</div>"
],
"challengeType": 0,
"type": "waypoint"
}
]
}

View File

@ -1,4 +1,4 @@
Everything to due with the server
Everything to do with the server.
One file that is not tracked here is `rev-manifest.json`.
It is generated at runtime and its contents changes as the contents

View File

@ -72,9 +72,9 @@ module.exports = function(app) {
'Feel free to email us at this address if you have ',
'any questions about Free Code Camp.\n',
'And if you have a moment, check out our blog: ',
'blog.freecodecamp.com.\n\n',
'medium.freecodecamp.com.\n\n',
'Good luck with the challenges!\n\n',
'- the Free Code Camp Volunteer Team'
'- the Free Code Camp Team'
].join('')
};

View File

@ -1,7 +1,7 @@
import React from 'react';
import Router from 'react-router';
import { RoutingContext } from 'react-router';
import Fetchr from 'fetchr';
import Location from 'react-router/lib/Location';
import { createLocation } from 'history';
import debugFactory from 'debug';
import { app$ } from '../../common/app';
import { RenderToString } from 'thundercats-react';
@ -13,7 +13,8 @@ const debug = debugFactory('freecc:react-server');
const routes = [
'/hikes',
'/hikes/*',
'/jobs'
'/jobs',
'/jobs/*'
];
export default function reactSubRouter(app) {
@ -29,25 +30,25 @@ export default function reactSubRouter(app) {
function serveReactApp(req, res, next) {
const services = new Fetchr({ req });
const location = new Location(req.path, req.query);
const location = createLocation(req.path);
// returns a router wrapped app
app$(location)
app$({ location })
// if react-router does not find a route send down the chain
.filter(function({ initialState }) {
if (!initialState) {
.filter(function({ props}) {
if (!props) {
debug('react tried to find %s but got 404', location.pathname);
return next();
}
return !!initialState;
return !!props;
})
.flatMap(function({ initialState, AppCat }) {
.flatMap(function({ props, AppCat }) {
// call thundercats renderToString
// prefetches data and sets up it up for current state
debug('rendering to string');
return RenderToString(
AppCat(null, services),
React.createElement(Router, initialState)
React.createElement(RoutingContext, props)
);
})
// makes sure we only get one onNext and closes subscription

172
server/boot/certificate.js Normal file
View File

@ -0,0 +1,172 @@
import _ from 'lodash';
import dedent from 'dedent';
import { Observable } from 'rx';
import debugFactory from 'debug';
import {
ifNoUser401,
ifNoUserSend
} from '../utils/middleware';
import {
saveUser,
observeQuery
} from '../utils/rx';
import {
frontEndChallangeId,
fullStackChallangeId
} from '../utils/constantStrings.json';
import {
completeCommitment$
} from '../utils/commit';
const debug = debugFactory('freecc:certification');
const sendMessageToNonUser = ifNoUserSend(
'must be logged in to complete.'
);
function isCertified(frontEndIds, { completedChallenges, isFrontEndCert }) {
if (isFrontEndCert) {
return true;
}
return _.every(frontEndIds, ({ id }) => {
return _.some(completedChallenges, (challenge) => {
return challenge.id === id || challenge._id === id;
});
});
}
export default function certificate(app) {
const router = app.loopback.Router();
const { Challenge } = app.models;
const frontEndChallangeIds$ = observeQuery(
Challenge,
'findById',
frontEndChallangeId,
{
id: true,
tests: true,
name: true,
challengeType: true
}
)
.shareReplay();
const fullStackChallangeIds$ = observeQuery(
Challenge,
'findById',
fullStackChallangeId,
{
id: true,
tests: true,
name: true,
challengeType: true
}
)
.shareReplay();
router.post(
'/certificate/verify/front-end',
ifNoUser401,
verifyCert
);
router.post(
'/certificate/verify/full-stack',
ifNoUser401,
verifyCert
);
router.post(
'/certificate/honest',
sendMessageToNonUser,
postHonest
);
app.use(router);
function verifyCert(req, res, next) {
const isFront = req.path.split('/').pop() === 'front-end';
Observable.just({})
.flatMap(() => {
if (isFront) {
return frontEndChallangeIds$;
}
return fullStackChallangeIds$;
})
.flatMap(challenge => {
const { user } = req;
const {
id,
tests,
name,
challengeType
} = challenge;
if (
isFront && !user.isFrontEndCert && isCertified(tests, user) ||
!isFront && !user.isFullStackCert && isCertified(tests, user)
) {
debug('certified');
if (isFront) {
user.isFrontEndCert = true;
} else {
user.isFullStackCert = true;
}
user.completedChallenges.push({
id,
name,
completedDate: new Date(),
challengeType
});
return saveUser(user)
// If user has commited to nonprofit,
// this will complete his pledge
.flatMap(
user => completeCommitment$(user),
(user, pledgeOrMessage) => {
if (typeof pledgeOrMessage === 'string') {
debug(pledgeOrMessage);
}
// we are only interested in the user object
// so we ignore return from completeCommitment$
return user;
}
);
}
return Observable.just(user);
})
.subscribe(
user => {
if (
isFront && user.isFrontEndCert ||
!isFront && user.isFullStackCert
) {
return res.status(200).send(true);
}
return res.status(200).send(
dedent`
Looks like you have not completed the neccessary steps.
Please return to the challenge map.
`
);
},
next
);
}
function postHonest(req, res, next) {
const { user } = req;
user.isHonest = true;
saveUser(user)
.subscribe(
(user) => {
res.status(200).send(!!user.isHonest);
},
next
);
}
}

View File

@ -9,50 +9,81 @@ import utils from '../utils';
import {
saveUser,
observeMethod,
observableQueryFromModel
observeQuery
} from '../utils/rx';
import {
userMigration,
ifNoUserRedirectTo,
ifNoUserSend
} from '../utils/middleware';
const isDev = process.env.NODE_ENV !== 'production';
const isBeta = !!process.env.BETA;
const debug = debugFactory('freecc:challenges');
const challengesRegex = /^(bonfire|waypoint|zipline|basejump)/i;
const firstChallenge = 'waypoint-say-hello-to-html-elements';
const firstChallenge = 'waypoint-learn-how-free-code-camp-works';
const challengeView = {
0: 'coursewares/showHTML',
1: 'coursewares/showJS',
2: 'coursewares/showVideo',
3: 'coursewares/showZiplineOrBasejump',
4: 'coursewares/showZiplineOrBasejump',
5: 'coursewares/showBonfire'
5: 'coursewares/showBonfire',
7: 'coursewares/showStep'
};
const dasherize = utils.dasherize;
const unDasherize = utils.unDasherize;
const getMDNLinks = utils.getMDNLinks;
function makeChallengesUnique(challengeArr) {
// clone and reverse challenges
// then filter by unique id's
// then reverse again
return _.uniq(challengeArr.slice().reverse(), 'id').reverse();
}
function numberWithCommas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
function updateUserProgress(user, challengeId, completedChallenge) {
const alreadyCompleted = user.completedChallenges.some(({ id }) => {
return id === challengeId;
let { completedChallenges } = user;
// migrate user challenges object to remove
/* if (!user.isUniqMigrated) {
user.isUniqMigrated = true;
completedChallenges = user.completedChallenges =
makeChallengesUnique(completedChallenges);
}*/
const indexOfChallenge = _.findIndex(completedChallenges, {
id: challengeId
});
const alreadyCompleted = indexOfChallenge !== -1;
if (!alreadyCompleted) {
user.progressTimestamps.push({
timestamp: Date.now(),
completedChallenge
completedChallenge: challengeId
});
}
user.completedChallenges.push(completedChallenge);
return user;
}
const oldCompletedChallenge = completedChallenges[indexOfChallenge];
user.completedChallenges[indexOfChallenge] =
Object.assign(
{},
completedChallenge,
{
completedDate: oldCompletedChallenge.completedDate,
lastUpdated: completedChallenge.completedDate
}
);
return user;
}
module.exports = function(app) {
const router = app.loopback.Router();
@ -76,6 +107,9 @@ module.exports = function(app) {
null,
Scheduler.default
))
// filter out all challenges that have isBeta flag set
// except in development or beta site
.filter(challenge => isDev || isBeta || !challenge.isBeta)
.shareReplay();
// create a stream of challenge blocks
@ -100,9 +134,6 @@ module.exports = function(app) {
const userCount$ = observeMethod(User, 'count');
const send200toNonUser = ifNoUserSend(true);
const redirectNonUser = ifNoUserRedirectTo(
'/challenges/learn-how-free-code-camp-works'
);
router.post(
'/completed-challenge/',
@ -120,31 +151,20 @@ module.exports = function(app) {
completedBonfire
);
// the follow routes are covered by userMigration
router.use(userMigration);
router.get('/map', challengeMap);
router.get(
'/challenges/next-challenge',
redirectNonUser,
returnNextChallenge
);
router.get('/challenges/:challengeName', returnIndividualChallenge);
router.get(
'/challenges/',
redirectNonUser,
returnCurrentChallenge
);
app.use(router);
function returnNextChallenge(req, res, next) {
let nextChallengeName = firstChallenge;
const challengeId = req.user.currentChallenge ?
req.user.currentChallenge.challengeId :
'bd7123c8c441eddfaeb5bdef';
const challengeId = req.query.id;
// find challenge
return challenge$
@ -165,9 +185,9 @@ module.exports = function(app) {
'could not find challenge block for ' + challenge.block
);
}
const nextBlock$ = blocks$.elementAt(blockIndex + 1);
const firstChallengeOfNextBlock$ = nextBlock$
.map(block => block.challenges[0]);
const firstChallengeOfNextBlock$ = blocks$
.elementAt(blockIndex + 1, {})
.map(({ challenges = [] }) => challenges[0]);
return blocks$
.elementAt(blockIndex)
@ -196,19 +216,19 @@ module.exports = function(app) {
});
})
.map(nextChallenge => {
if (!nextChallenge) {
return null;
}
nextChallengeName = nextChallenge.dashedName;
return nextChallengeName;
})
.flatMap(() => {
return saveUser(req.user);
})
.subscribe(
function() {},
next,
function() {
debug('next challengeName', nextChallengeName);
if (!nextChallengeName || nextChallengeName === firstChallenge) {
req.flash('errors', {
req.flash('info', {
msg: dedent`
Once you have completed all of our challenges, you should
join our <a href=\"//gitter.im/freecodecamp/HalfWayClub\"
@ -223,36 +243,9 @@ module.exports = function(app) {
);
}
function returnCurrentChallenge(req, res, next) {
Observable.just(req.user)
.flatMap(user => {
if (!req.user.currentChallenge) {
return challenge$
.first()
.flatMap(challenge => {
user.currentChallenge = {
challengeId: challenge.id,
challengeName: challenge.name,
dashedName: challenge.dashedName
};
return saveUser(user);
});
}
return Observable.just(user);
})
.map(user => user.currentChallenge.dashedName)
.subscribe(
function(challengeName) {
res.redirect('/challenges/' + challengeName);
},
next,
function() {
}
);
}
function returnIndividualChallenge(req, res, next) {
const origChallengeName = req.params.challengeName;
const solutionCode = req.query.solution;
const unDashedName = unDasherize(origChallengeName);
const challengeName = challengesRegex.test(unDashedName) ?
@ -266,7 +259,7 @@ module.exports = function(app) {
.filter((challenge) => {
return testChallengeName.test(challenge.name);
})
.lastOrDefault(null)
.last({ defaultValue: null })
.flatMap(challenge => {
// Handle not found
@ -282,25 +275,22 @@ module.exports = function(app) {
}
if (dasherize(challenge.name) !== origChallengeName) {
return Observable.just('/challenges/' + dasherize(challenge.name));
let redirectUrl = `/challenges/${dasherize(challenge.name)}`;
if (solutionCode) {
redirectUrl += `?solution=${encodeURIComponent(solutionCode)}`;
}
if (challenge) {
if (req.user) {
req.user.currentChallenge = {
challengeId: challenge.id,
challengeName: challenge.name,
dashedName: challenge.dashedName
};
return Observable.just(redirectUrl);
}
// save user does nothing if user does not exist
return saveUser(req.user)
.map(() => ({
return Observable.just({
title: challenge.name,
dashedName: origChallengeName,
name: challenge.name,
details: challenge.description,
description: challenge.description,
tests: challenge.tests,
challengeSeed: challenge.challengeSeed,
verb: utils.randomVerb(),
@ -317,8 +307,7 @@ module.exports = function(app) {
MDNlinks: getMDNLinks(challenge.MDNlinks),
// htmls specific
environment: utils.whichEnvironment()
}));
}
});
})
.subscribe(
function(data) {
@ -347,7 +336,7 @@ module.exports = function(app) {
challengeType: 5
};
observableQueryFromModel(
observeQuery(
User,
'findOne',
{ where: { username: ('' + completedWith).toLowerCase() } }
@ -475,7 +464,7 @@ module.exports = function(app) {
verified: false
};
observableQueryFromModel(
observeQuery(
User,
'findOne',
{ where: { username: completedWith.toLowerCase() } }
@ -526,6 +515,7 @@ module.exports = function(app) {
}
function challengeMap({ user = {} }, res, next) {
let lastCompleted;
const daysRunning = moment().diff(new Date('10/15/2014'), 'days');
// if user
@ -558,17 +548,26 @@ module.exports = function(app) {
}
return sum;
}, 0);
const isBeta = _.every(blockArray, 'isBeta');
return {
isBeta,
name: blockArray[0].block,
dashedName: dasherize(blockArray[0].block),
challenges: blockArray,
completed: completedCount / blockArray.length * 100
completed: completedCount / blockArray.length * 100,
time: blockArray[0] && blockArray[0].time || "???"
};
})
.filter(({ name }) => name !== 'Hikes')
// turn stream of blocks into a stream of an array
.toArray();
.toArray()
.doOnNext((blocks) => {
const lastCompletedBlock = _.findLast(blocks, (block) => {
return block.completed === 100;
});
lastCompleted = lastCompletedBlock && lastCompletedBlock.name || null;
});
Observable.combineLatest(
camperCount$,
@ -581,6 +580,7 @@ module.exports = function(app) {
blocks,
daysRunning,
camperCount,
lastCompleted,
title: "A map of all Free Code Camp's Challenges"
});
},

224
server/boot/commit.js Normal file
View File

@ -0,0 +1,224 @@
import _ from 'lodash';
import { Observable } from 'rx';
import debugFactory from 'debug';
import dedent from 'dedent';
import nonprofits from '../utils/commit.json';
import {
commitGoals,
completeCommitment$
} from '../utils/commit';
import {
unDasherize
} from '../utils';
import {
observeQuery,
saveInstance
} from '../utils/rx';
import {
ifNoUserRedirectTo
} from '../utils/middleware';
const sendNonUserToFront = ifNoUserRedirectTo('/');
const sendNonUserToCommit = ifNoUserRedirectTo(
'/commit',
'Must be signed in to update commit'
);
const debug = debugFactory('freecc:commit');
function findNonprofit(name) {
let nonprofit;
if (name) {
nonprofit = _.find(nonprofits, (nonprofit) => {
return name === nonprofit.name;
});
}
nonprofit = nonprofit || nonprofits[0];
return nonprofit;
}
export default function commit(app) {
const router = app.loopback.Router();
const { Pledge } = app.models;
router.get(
'/commit',
commitToNonprofit
);
router.get(
'/commit/pledge',
sendNonUserToFront,
pledge
);
router.get(
'/commit/directory',
renderDirectory
);
router.post(
'/commit/stop-commitment',
sendNonUserToCommit,
stopCommit
);
router.post(
'/commit/complete-goal',
sendNonUserToCommit,
completeCommitment
);
app.use(router);
function commitToNonprofit(req, res, next) {
const { user } = req;
let nonprofitName = unDasherize(req.query.nonprofit);
debug('looking for nonprofit', nonprofitName);
const nonprofit = findNonprofit(nonprofitName);
Observable.just(user)
.flatMap(user => {
if (user) {
debug('getting user pledge');
return observeQuery(user, 'pledge');
}
return Observable.just();
})
.subscribe(
pledge => {
if (pledge) {
debug('found previous pledge');
req.flash('info', {
msg: dedent`
Looks like you already have a pledge to ${pledge.displayName}.
Hitting commit here will replace your old commitment.
`
});
}
res.render(
'commit/',
Object.assign(
{
title: 'Commit to a nonprofit. Commit to your goal.',
pledge,
frontEndCert: commitGoals.frontEndCert,
fullStackCert: commitGoals.fullStackCert
},
nonprofit
)
);
},
next
);
}
function pledge(req, res, next) {
const { user } = req;
const {
nonprofit: nonprofitName = 'girl develop it',
amount = '5',
goal = commitGoals.frontEndCert
} = req.query;
const nonprofit = findNonprofit(nonprofitName);
observeQuery(user, 'pledge')
.flatMap(oldPledge => {
// create new pledge for user
const pledge = Pledge(
Object.assign(
{
amount,
goal,
userId: user.id
},
nonprofit
)
);
if (oldPledge) {
debug('user already has pledge, creating a new one');
// we orphan last pledge since a user only has one pledge at a time
oldPledge.userId = '';
oldPledge.formerUser = user.id;
oldPledge.endDate = new Date();
oldPledge.isOrphaned = true;
return saveInstance(oldPledge)
.flatMap(() => {
return saveInstance(pledge);
});
}
return saveInstance(pledge);
})
.subscribe(
({ displayName, goal, amount }) => {
req.flash('success', {
msg: dedent`
Congratulations, you have committed to giving
${displayName} $${amount} each month until you have completed
your ${goal}.
`
});
res.redirect('/' + user.username);
},
next
);
}
function renderDirectory(req, res) {
res.render('commit/directory', {
title: 'Commit Directory',
nonprofits
});
}
function completeCommitment(req, res, next) {
const { user } = req;
return completeCommitment$(user)
.subscribe(
msgOrPledge => {
if (typeof msgOrPledge === 'string') {
return res.send(msgOrPledge);
}
return res.send(true);
},
next
);
}
function stopCommit(req, res, next) {
const { user } = req;
observeQuery(user, 'pledge')
.flatMap(pledge => {
if (!pledge) {
return Observable.just();
}
pledge.formerUserId = pledge.userId;
pledge.userId = null;
pledge.isOrphaned = true;
pledge.dateEnded = new Date();
return saveInstance(pledge);
})
.subscribe(
pledge => {
let msg = `You have successfully stopped your pledge.`;
if (!pledge) {
msg = `No pledge found for user ${user.username}.`;
}
req.flash('errors', { msg });
return res.redirect(`/${user.username}`);
},
next
);
}
}

View File

@ -1,7 +1,7 @@
import { defaultProfileImage } from '../../common/utils/constantStrings.json';
const message =
'Learn to Code JavaScript and get a Coding Job by Helping Nonprofits';
'Learn to Code and Build Projects for Nonprofits';
module.exports = function(app) {
var router = app.loopback.Router();
@ -22,7 +22,7 @@ module.exports = function(app) {
function index(req, res) {
if (req.user) {
return res.render('resources/get-started', { title: message });
return res.redirect('/map');
}
res.render('home', { title: message });
}

View File

@ -64,23 +64,6 @@ module.exports = function(app) {
return res.redirect('../nonprofit/' + dashedNameFull);
}
// We need to create logic that verifies completion.
// Defaulting to false for now.
// var buttonActive = false;
// if (
// req.user &&
// req.user.completedCoursewares.length > 63
// ) {
// var hasShownInterest =
// nonprofit.interestedCampers.filter(function(user) {
// return user.username === req.user.username;
// });
//
// if (hasShownInterest.length === 0) {
// buttonActive = true;
// }
// }
res.render('nonprofits/show', {
dashedName: dashedNameFull,
title: nonprofit.name,

View File

@ -5,6 +5,8 @@ var Rx = require('rx'),
request = require('request'),
debug = require('debug')('freecc:cntr:resources'),
constantStrings = require('../utils/constantStrings.json'),
labs = require('../resources/labs.json'),
testimonials = require('../resources/testimonials.json'),
secrets = require('../../config/secrets');
module.exports = function(app) {
@ -27,11 +29,12 @@ module.exports = function(app) {
router.get('/nonprofits', nonprofits);
router.get('/nonprofits-form', nonprofitsForm);
router.get('/our-sponsors', sponsors);
router.get('/jobs-form', jobsForm);
router.get('/unsubscribe/:email', unsubscribe);
router.get('/unsubscribed', unsubscribed);
router.get('/get-started', getStarted);
router.get('/submit-cat-photo', submitCatPhoto);
router.get('/labs', showLabs);
router.get('/stories', showTestimonials);
app.use(router);
@ -180,6 +183,20 @@ module.exports = function(app) {
res.redirect('https://gitter.im/FreeCodeCamp/FreeCodeCamp');
}
function showLabs(req, res) {
res.render('resources/labs', {
title: 'Projects Built by Free Code Camp Students',
projects: labs
});
}
function showTestimonials(req, res) {
res.render('resources/stories', {
title: 'Stories from Happy Free Code Camp Campers',
stories: testimonials
});
}
function submitCatPhoto(req, res) {
res.send('Submitted!');
}
@ -190,20 +207,6 @@ module.exports = function(app) {
});
}
function jobsForm(req, res) {
res.render('resources/jobs-form', {
title: 'Employer Partnership Form for Job Postings,' +
' Recruitment and Corporate Sponsorships'
});
}
function catPhotoSubmit(req, res) {
res.send(
'Success! You have submitted your cat photo. Return to your website ' +
'by typing any letter into your code editor.'
);
}
function sponsors(req, res) {
res.render('sponsors/sponsors', {
title: 'The Sponsors who make Free Code Camp Possible'

View File

@ -12,6 +12,10 @@ module.exports = function(app) {
res.redirect(301, '/pmi-acp-agile-project-managers');
});
router.get('/wiki', function(req, res) {
res.redirect(301, '//github.com/freecodecamp/freecodecamp/wiki');
});
router.get('/privacy', function(req, res) {
res.redirect(
301, "//github.com/FreeCodeCamp/freecodecamp/wiki/Free-Code-Camp's-Privacy-Policy"

View File

@ -12,13 +12,18 @@ var Rx = require('rx'),
validator = require('validator'),
secrets = require('../../config/secrets');
var foundationDate = 1413298800000;
var time48Hours = 172800000;
import {
ifNoUser401,
ifNoUserRedirectTo
} from '../utils/middleware';
var unDasherize = utils.unDasherize;
var dasherize = utils.dasherize;
var getURLTitle = utils.getURLTitle;
var ifNoUser401 = require('../utils/middleware').ifNoUser401;
const foundationDate = 1413298800000;
const time48Hours = 172800000;
const unDasherize = utils.unDasherize;
const dasherize = utils.dasherize;
const getURLTitle = utils.getURLTitle;
const sendNonUserToNews = ifNoUserRedirectTo('/news');
function hotRank(timeValue, rank) {
/*
@ -62,8 +67,16 @@ module.exports = function(app) {
router.get('/news/hot', hotJSON);
router.get('/stories/hotStories', hotJSON);
router.get('/stories/submit', submitNew);
router.get('/stories/submit/new-story', preSubmit);
router.get(
'/stories/submit',
sendNonUserToNews,
submitNew
);
router.get(
'/stories/submit/new-story',
sendNonUserToNews,
preSubmit
);
router.post('/stories/preliminary', ifNoUser401, newStory);
router.post('/stories/', ifNoUser401, storySubmission);
router.get('/news/', hot);
@ -102,17 +115,25 @@ module.exports = function(app) {
}
function submitNew(req, res) {
if (!req.user.isGithubCool) {
req.flash('errors', {
msg: 'You must link GitHub with your account before you can post' +
' on Camper News.'
});
return res.redirect('/news');
}
return res.render('stories/index', {
title: 'Submit a new story to Camper News',
page: 'submit'
});
}
function preSubmit(req, res, next) {
function preSubmit(req, res) {
var data = req.query;
if (typeof data.url !== 'string') {
req.flash('errors', { msg: 'No URL supplied with story' });
return next(new TypeError('No URL supplied with story'));
return res.redirect('/news');
}
var cleanedData = cleanData(data.url);
@ -170,7 +191,6 @@ module.exports = function(app) {
title: story.headline,
link: story.link,
originalStoryLink: dashedName,
originalStoryAuthorEmail: story.author.email || '',
author: story.author,
rank: story.upVotes.length,
upVotes: story.upVotes,
@ -265,8 +285,11 @@ module.exports = function(app) {
}
function newStory(req, res, next) {
if (!req.user) {
return next(new Error('Must be logged in'));
if (!req.user.isGithubCool) {
req.flash('errors', {
msg: 'You must authenticate with Github to post to Camper News'
});
return res.redirect('/news');
}
var url = req.body.data.url;
@ -373,13 +396,11 @@ module.exports = function(app) {
author: {
picture: req.user.picture,
userId: req.user.id,
username: req.user.username,
email: req.user.email
username: req.user.username
},
image: data.image,
storyLink: storyLink,
metaDescription: data.storyMetaDescription,
originalStoryAuthorEmail: req.user.email
metaDescription: data.storyMetaDescription
});
return saveInstance(newStory);
});

View File

@ -1,12 +1,25 @@
import _ from 'lodash';
import async from 'async';
import dedent from 'dedent';
import moment from 'moment';
import { Observable } from 'rx';
import debugFactory from 'debug';
import { ifNoUser401 } from '../utils/middleware';
import {
frontEndChallangeId,
fullStackChallangeId
} from '../utils/constantStrings.json';
import { ifNoUser401, ifNoUserRedirectTo } from '../utils/middleware';
import { observeQuery } from '../utils/rx';
const debug = debugFactory('freecc:boot:user');
const daysBetween = 1.5;
const sendNonUserToMap = ifNoUserRedirectTo('/map');
function replaceScriptTags(value) {
return value
.replace(/<script>/gi, 'fccss')
.replace(/<\/script>/gi, 'fcces');
}
function calcCurrentStreak(cals) {
const revCals = cals.concat([Date.now()]).slice().reverse();
@ -52,7 +65,16 @@ function dayDiff([head, tail]) {
module.exports = function(app) {
var router = app.loopback.Router();
var User = app.models.User;
var Story = app.models.Story;
function findUserByUsername$(username, fields) {
return observeQuery(
User,
'findOne',
{
where: { username },
fields
}
);
}
router.get('/login', function(req, res) {
res.redirect(301, '/signin');
@ -68,15 +90,35 @@ module.exports = function(app) {
router.post('/reset-password', postReset);
router.get('/email-signup', getEmailSignup);
router.get('/email-signin', getEmailSignin);
router.get('/account/api', getAccountAngular);
router.get(
'/toggle-lockdown-mode',
sendNonUserToMap,
toggleLockdownMode
);
router.post(
'/account/delete',
ifNoUser401,
postDeleteAccount
);
router.get('/account/unlink/:provider', getOauthUnlink);
router.get('/account', getAccount);
// Ensure this is the last route!
router.get(
'/account',
sendNonUserToMap,
getAccount
);
router.get('/vote1', vote1);
router.get('/vote2', vote2);
// Ensure these are the last routes!
router.get(
'/:username/front-end-certification',
showCert
);
router.get(
'/:username/full-stack-certification',
showCert
);
router.get('/:username', returnUser);
app.use(router);
@ -114,45 +156,31 @@ module.exports = function(app) {
}
function getAccount(req, res) {
if (!req.user) {
return res.redirect('/');
}
res.render('account/account', {
title: 'Manage your Free Code Camp Account'
});
}
function getAccountAngular(req, res) {
res.json({
user: req.user || {}
});
const { username } = req.user;
return res.redirect('/' + username);
}
function returnUser(req, res, next) {
const username = req.params.username.toLowerCase();
const { path } = req;
User.findOne(
{ where: { username } },
function(err, user) {
{
where: { username },
include: 'pledge'
},
function(err, profileUser) {
if (err) {
return next(err);
}
if (!user) {
if (!profileUser) {
req.flash('errors', {
msg: `404: We couldn't find path ${ path }`
});
return res.redirect('/');
}
if (!user.isGithubCool && !user.isMigrationGrandfathered) {
req.flash('errors', {
msg: `
user ${ username } has not completed account signup
`
});
return res.redirect('/');
}
profileUser = profileUser.toJSON();
var cals = user
var cals = profileUser
.progressTimestamps
.map(objOrNum => {
return typeof objOrNum === 'number' ?
@ -161,10 +189,10 @@ module.exports = function(app) {
})
.sort();
user.currentStreak = calcCurrentStreak(cals);
user.longestStreak = calcLongestStreak(cals);
profileUser.currentStreak = calcCurrentStreak(cals);
profileUser.longestStreak = calcLongestStreak(cals);
const data = user
const data = profileUser
.progressTimestamps
.map((objOrNum) => {
return typeof objOrNum === 'number' ?
@ -179,39 +207,181 @@ module.exports = function(app) {
return data;
}, {});
const challenges = user.completedChallenges.filter(function(obj) {
const baseAndZip = profileUser.completedChallenges.filter(
function(obj) {
return obj.challengeType === 3 || obj.challengeType === 4;
});
}
);
const bonfires = user.completedChallenges.filter(function(obj) {
const bonfires = profileUser.completedChallenges.filter(function(obj) {
return obj.challengeType === 5 && (obj.name || '').match(/Bonfire/g);
});
const waypoints = profileUser.completedChallenges.filter(function(obj) {
return (obj.name || '').match(/^Waypoint/i);
});
res.render('account/show', {
title: 'Camper ' + user.username + '\'s portfolio',
username: user.username,
name: user.name,
isMigrationGrandfathered: user.isMigrationGrandfathered,
isGithubCool: user.isGithubCool,
location: user.location,
github: user.githubURL,
linkedin: user.linkedin,
google: user.google,
facebook: user.facebook,
twitter: user.twitter,
picture: user.picture,
progressTimestamps: user.progressTimestamps,
title: 'Camper ' + profileUser.username + '\'s portfolio',
username: profileUser.username,
name: profileUser.name,
isMigrationGrandfathered: profileUser.isMigrationGrandfathered,
isGithubCool: profileUser.isGithubCool,
isLocked: !!profileUser.isLocked,
pledge: profileUser.pledge,
isFrontEndCert: profileUser.isFrontEndCert,
isFullStackCert: profileUser.isFullStackCert,
isHonest: profileUser.isHonest,
location: profileUser.location,
calender: data,
challenges: challenges,
bonfires: bonfires,
moment: moment,
longestStreak: user.longestStreak,
currentStreak: user.currentStreak
github: profileUser.githubURL,
linkedin: profileUser.linkedin,
google: profileUser.google,
facebook: profileUser.facebook,
twitter: profileUser.twitter,
picture: profileUser.picture,
progressTimestamps: profileUser.progressTimestamps,
baseAndZip,
bonfires,
waypoints,
moment,
longestStreak: profileUser.longestStreak,
currentStreak: profileUser.currentStreak,
replaceScriptTags
});
}
);
}
function showCert(req, res, next) {
const username = req.params.username.toLowerCase();
const { user } = req;
const showFront = req.path.split('/').pop() === 'front-end-certification';
Observable.just(user)
.flatMap(user => {
if (user && user.username === username) {
return Observable.just(user);
}
return findUserByUsername$(username, {
isGithubCool: true,
isFrontEndCert: true,
isFullStackCert: true,
isHonest: true,
completedChallenges: true,
username: true,
name: true
});
})
.subscribe(
(user) => {
if (!user) {
req.flash('errors', {
msg: `404: We couldn't find the user ${username}`
});
return res.redirect('/');
}
if (!user.isGithubCool) {
req.flash('errors', {
msg: dedent`
This user needs to link GitHub with their account
in order to display this certificate to the public.
`
});
return res.redirect('back');
}
if (user.isLocked) {
req.flash('errors', {
msg: dedent`
${username} has chosen to hide their work from the public.
They need to unhide their work in order for this certificate to
be verifiable.
`
});
return res.redirect('back');
}
if (!user.isHonest) {
req.flash('errors', {
msg: dedent`
${username} has not agreed to our Academic Honesty Pledge yet.
`
});
return res.redirect('back');
}
if (
showFront && user.isFrontEndCert ||
!showFront && user.isFullStackCert
) {
var { completedDate = new Date() } =
_.find(user.completedChallenges, {
id: showFront ?
frontEndChallangeId :
fullStackChallangeId
}) || {};
return res.render(
showFront ?
'certificate/front-end.jade' :
'certificate/full-stack.jade',
{
username: user.username,
date: moment(new Date(completedDate))
.format('MMMM, Do YYYY'),
name: user.name
}
);
}
req.flash('errors', {
msg: showFront ?
`Looks like user ${username} is not Front End certified` :
`Looks like user ${username} is not Full Stack certified`
});
res.redirect('back');
},
next
);
}
function toggleLockdownMode(req, res, next) {
if (req.user.isLocked === true) {
req.user.isLocked = false;
return req.user.save(function(err) {
if (err) { return next(err); }
req.flash('success', {
msg: dedent`
Other people can now view all your challenge solutions.
You can change this back at any time in the "Manage My Account"
section at the bottom of this page.
`
});
res.redirect('/' + req.user.username);
});
}
req.user.isLocked = true;
return req.user.save(function(err) {
if (err) { return next(err); }
req.flash('success', {
msg: dedent`
All your challenge solutions are now hidden from other people.
You can change this back at any time in the "Manage My Account"
section at the bottom of this page.
`
});
res.redirect('/' + req.user.username);
});
}
function postDeleteAccount(req, res, next) {
User.destroyById(req.user.id, function(err) {
if (err) { return next(err); }
@ -221,25 +391,6 @@ module.exports = function(app) {
});
}
function getOauthUnlink(req, res, next) {
var provider = req.params.provider;
User.findById(req.user.id, function(err, user) {
if (err) { return next(err); }
user[provider] = null;
user.tokens =
_.reject(user.tokens, function(token) {
return token.kind === provider;
});
user.save(function(err) {
if (err) { return next(err); }
req.flash('info', { msg: provider + ' account has been unlinked.' });
res.redirect('/account');
});
});
}
function getReset(req, res) {
if (!req.accessToken) {
req.flash('errors', { msg: 'access token invalid' });
@ -281,11 +432,6 @@ module.exports = function(app) {
});
}
/**
* POST /forgot
* Create a random token, then the send user an email with a reset link.
*/
function postForgot(req, res) {
const errors = req.validationErrors();
const email = req.body.email.toLowerCase();
@ -312,6 +458,7 @@ module.exports = function(app) {
});
}
/*
function updateUserStoryPictures(userId, picture, username, cb) {
Story.find({ 'author.userId': userId }, function(err, stories) {
if (err) { return cb(err); }
@ -332,4 +479,35 @@ module.exports = function(app) {
});
});
}
*/
function vote1(req, res, next) {
if (req.user) {
req.user.tshirtVote = 1;
req.user.save(function(err) {
if (err) { return next(err); }
req.flash('success', { msg: 'Thanks for voting!' });
res.redirect('/map');
});
} else {
req.flash('error', { msg: 'You must be signed in to vote.' });
res.redirect('/map');
}
}
function vote2(req, res, next) {
if (req.user) {
req.user.tshirtVote = 2;
req.user.save(function(err) {
if (err) { return next(err); }
req.flash('success', { msg: 'Thanks for voting!' });
res.redirect('/map');
});
} else {
req.flash('error', {msg: 'You must be signed in to vote.'});
res.redirect('/map');
}
}
};

View File

@ -15,7 +15,7 @@
"initial": {
"compression": {},
"morgan": {
"params": "dev"
"params": ":status :method :response-time ms - :url"
}
},
"session": {

View File

@ -12,20 +12,27 @@ const pathsOfNoReturn = [
'css'
];
const pathsWhiteList = [
'news',
'challenges',
'map',
'news'
];
const pathsOfNoReturnRegex = new RegExp(pathsOfNoReturn.join('|'), 'i');
const whiteListRegex = new RegExp(pathsWhiteList.join('|'), 'i');
export default function addReturnToUrl() {
return function(req, res, next) {
// Remember original destination before login.
var path = req.path.split('/')[1];
if (req.method !== 'GET') {
return next();
}
if (pathsOfNoReturnRegex.test(path)) {
return next();
}
if (/\/stories\/\w+/i.test(req.path)) {
if (
req.method !== 'GET' ||
pathsOfNoReturnRegex.test(path) ||
!whiteListRegex.test(path) ||
(/news/i).test(path) && (/hot/i).test(req.path)
) {
return next();
}
req.session.returnTo = req.path;

View File

@ -55,6 +55,7 @@ export default function csp() {
return helmet.csp({
defaultSrc: trusted,
scriptSrc: [
'https://*.gitter.im',
'*.optimizely.com',
'*.aspnetcdn.com',
'*.d3js.org',
@ -72,7 +73,8 @@ export default function csp() {
imgSrc: [
// allow all input since we have user submitted images for
// public profile
'*'
'*',
'data:'
].concat(trusted),
fontSrc: [
'*.googleapis.com',

View File

@ -1,6 +1,8 @@
import manifest from '../rev-manifest.json';
const __DEV__ = process.env.NODE_ENV === 'development';
const manifestPath = '../rev-manifest.json';
export default function({ globalPrepend = '' } = {}) {
function rev(manifest, scopedPrepend, asset) {
@ -13,7 +15,10 @@ export default function({ globalPrepend = '' } = {}) {
// this means we do not need to restart server on every change to
// client code
if (__DEV__) {
const manifest = require('../rev-manifest.json');
// we first need to remove the manifest from require cache
delete require.cache[require.resolve(manifestPath)];
// and re-require
const manifest = require(manifestPath);
res.locals.rev = rev.bind(null, manifest);
return next();
}

View File

@ -47,6 +47,10 @@
"dataSource": "db",
"public": true
},
"pledge": {
"dataSource": "db",
"public": true
},
"user": {
"dataSource": "db",
"public": true

View File

@ -0,0 +1,37 @@
[
{
"camper": "johnstonbl01",
"name": "Clementine.js",
"url": "http://johnstonbl01.github.io/clementinejs/",
"description": "The elegant and lightweight boilerplate for full stack JavaScript.",
"image": "http://i.imgur.com/ib1wOho.png"
},
{
"camper": "adventurebear",
"name": "Coding Bootcamp Cost Calculator",
"url": "http://www.freecodecamp.com/coding-bootcamp-cost-calculator",
"description": "This d3.js-powered coding bootcamp cost calculator takes into account tuition, financing, lost wages and cost of living.",
"image": "https://qph.is.quoracdn.net/main-qimg-670d6a0c5b01f74138e777732994240f?convert_to_webp=true"
},
{
"camper": "ericdouglas",
"name": "Open Source Society",
"url": "https://github.com/open-source-society/computer-science",
"description": "A path to a free education in Computer Science.",
"image": "https://camo.githubusercontent.com/c42438055d3fee26b29e6d046fd8d06ebff3db20/687474703a2f2f692e696d6775722e636f6d2f6838786a72726a2e706e67"
},
{
"camper": "akiralaine",
"name": "Camper News Bot",
"url": "https://twitter.com/campernewsbot",
"description": "This twitter bot tweets out Camper News stories once they hit 5 upvotes.",
"image": "https://pbs.twimg.com/media/CLXOFLPWIAEHYPJ.png"
},
{
"camper": "roelver",
"name": "Free Code Camp Top 100 Campers",
"url": "http://fcctop100.herokuapp.com/",
"description": "This leaderboard tracks the campers who have been most active (completing challenges, helping other campers) in the past 30 days.",
"image": "http://i.imgur.com/4CrQfFi.png"
}
]

View File

@ -0,0 +1,555 @@
[
{
"camper": "Meta Hirschl",
"quote": "By building a robust and highly functional web app I was able to not only increase my confidence but was able to show potential employers what I was able to create. Both were huge for me and led me to getting a fantastic job.",
"github": "MetaCoderHirschl",
"linkedin": "https://www.linkedin.com/profile/view?id=ADEAAAKX2fEBfeZ1GVdOh-c0zzkYZKw38o8qzow&authType=NAME_SEARCH&authToken=hfRS&locale=en_US&srchid=147930701444634954491&srchindex=1&srchtotal=1&trk=vsrp_people_res_photo&trkInfo=VSRPsearchId%3A147930701444634954491%2CVSRPtargetId%3A43506161%2CVSRPcmpt%3Aprimary%2CVSRPnm%3Atrue%2CauthType%3ANAME_SEARCH",
"image": "https://media.licdn.com/media/p/6/005/0ac/31c/05f0e58.jpg"
},
{
"camper": "Branden Byers",
"quote": "My goal was to become employed by the end of 2015. Instead, I ended up with a job at the beginning of 2015. This was directly related to my work at Free Code Camp.",
"github": "brandenbyers",
"linkedin": "https://www.linkedin.com/in/brandenbyers",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/4/005/0a0/1e4/378908c.jpg"
},
{
"camper": "Bruna Torman Reseres Franasa",
"quote": "Im now receiving offers for internships. I have no experience in IT, but now good things are happening!",
"github": "brunatrf",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABVPh9IB730qyshrsqO1hDNNRUL-X_4i8n0&authType=NAME_SEARCH&authToken=YYn-&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A357533650%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907147451%2Ctas%3Abruna",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/8/005/09e/16e/32c3d3f.jpg"
},
{
"camper": "Maxim Orlov",
"quote": "I started Free Code Camp with zero knowledge of web development. 6 months later, I landed my first job as a back end engineer.",
"github": "Maximization",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAo83nwBF57LpD9mZlm5dH6OcovOpYKPs3k&authType=NAME_SEARCH&authToken=yG4h&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A171761276%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635014777%2Ctas%3AMaxim%20Orlov",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAALJAAAAJGI5ZGFhODA0LWI4MzAtNDU5Ny04NjU3LTIwMjdhMmIxYjFjNg.jpg"
},
{
"camper": "Alexander Black, Jr.",
"quote": "My work on a nonprofit project gave me the opportunity to learn how to build Chrome extensions and showcase my skills as a full-stack developer.",
"github": "alexblackjr",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA553L4BgfgBR-M9RQc7x5matd6FUx3a6-I&authType=NAME_SEARCH&authToken=TW_a&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A242867390%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444634592237%2Ctas%3Aalexander%20black%20jr",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAANmAAAAJDQ1ZWIxMmVjLTAwNjUtNDFlNS04OWVhLTk4ZGZkNmViODkxNw.jpg"
},
{
"camper": "Cristiane Henriques",
"quote": "I am getting more work contacts after including Free Code Camp on my CV and my LinkedIn.",
"github": "CrisHenriques",
"linkedin": "https://www.linkedin.com/in/crishenriques",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAKEAAAAJGFjMTBjZWY5LTE2ZWMtNGU2OC05MTk3LTdkZjUyYWI1NjA5NQ.jpg"
},
{
"camper": "Viktor Bakurin",
"quote": "During my work on Free Code Camp's nonprofit projects, I found a MEAN stack position outside of my home country. Now I work in Budapest.",
"github": "letalumil",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAq6G3QBA1DIwFZGrS4DGqDzBDTzFjrbNQo&authType=NAME_SEARCH&authToken=QoJ0&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A179968884%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635040141%2Ctas%3AViktor%20Bakurin",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAM3AAAAJDVkZThkNjk3LWY4MTgtNGNmMS05MTZkLTkxZDljOGEzMGM5Nw.jpg"
},
{
"camper": "Ashley Drake",
"quote": "Free Code Camp helped me get my first engineering job. This amazing community made my career switch a lot easier and more fun.",
"github": "aldraco",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABcdBycB1iVHvcW7N3yVK-18ES7Nrxx2jbE&authType=NAME_SEARCH&authToken=gKNN&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A387778343%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635725853%2Ctas%3Aashley%20",
"image": "http://i.imgur.com/xzDoJef.jpg"
},
{
"camper": "Brian Grant",
"quote": "I've received new employment opportunities and I have not even finished Free Code Camp's first 800 hours of training yet.",
"github": "codeseekingman",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAEUqXoBFOq1SWQrBsTMHG4ij9Ss4Qqnrtg&authType=NAME_SEARCH&authToken=a85-&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A18131322%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635878707%2Ctas%3Abrian%20grant",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAANEAAAAJGY5ZjZkMDVjLTJhY2EtNDZjYS1iMDk5LTY0ZDliN2EyODUxMQ.jpg"
},
{
"camper": "Thomas Joseph Izen",
"quote": "After spending lots of time trying different sites that aim to teach people how to code, FreeCodeCamp has been different from the beginning. They provide the best and most organized track for anyone at any level to learn how to code and build an amazing, marketable portfolio.",
"github": "TommyIzen",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA79qIYB_RHmvOP59S6VPK3Lm06oG8fM6dw&authType=NAME_SEARCH&authToken=PfeR&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A251504774%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444636112016%2Ctas%3AThomas%20%20Izen",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAMaAAAAJGRjZTQ4MTdmLTZmZGItNGFhNS1hNTE0LWJmYjFhZDY3YmM3MQ.jpg"
},
{
"camper": "Lori Becker",
"quote": "After graduating with a Masters degree in computer science, I could not share any of my code with employers (university policy: fear of aiding cheating). With FreeCodeCamp, I was able to develop a small portfolio.",
"github": "LCBecker",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAADrtuwBOA_0ihkKIbUFXoXskXikQT9uVeo&authType=NAME_SEARCH&authToken=sctO&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A15447788%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907195702%2Ctas%3Alori",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/1/005/080/392/295a574.jpg"
},
{
"camper": "Robert Trammel",
"quote": "I'm working a job integrating JavaScript into FileMaker and doing some custom web publishing for a school district. I've also have job offers from Apple and a few technology firms around the country. If it wasn't for Free Code Camp, I'd still be in the dark with some really awesome but irrelevant skills.",
"github": "comajama",
"linkedin": "https://www.linkedin.com/profile/view?id=AAIAABQsM30BEAI6xyAhk-OqbBNUJL0WD2uA3GE&authType=NAME_SEARCH&authToken=4xB-&trk=Skyline_click_NPS&sl=NPS%3B147930701444636308659%3B1%3B147930701444636308659%3B",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAAIBAAAAJDI5YjRmMTRmLTFjNWItNGQ5ZC05MTNjLTA0MWQ0YjRhOTdhNQ.jpg"
},
{
"camper": "Brian Atkins",
"quote": "I'm spending less time then I am used to on Free Code Camp because people have begun to hire me to work on their projects. Free Code Camp has provided me the foundation I have needed to get these jobs.",
"github": "BrianAtk",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAABtTx0BmDzmB7eDGOkAJbRw8RZdvysreso&authType=NAME_SEARCH&authToken=CecH&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A7163677%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444636556530%2Ctas%3ABrian%20Atkins",
"image": "https://media.licdn.com/media/p/8/000/2aa/36c/2d218a8.jpg"
},
{
"camper": "Andrea Goulet",
"quote": "Before enrolling in Free Code Camp, I was nervous when people asked me, \"Do you code?\", Now, I answer with a confident \"YES!\"",
"github": "andreagoulet",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAA4KWYB-mCMwEU3LvDHXt6H0rVHbBvszq0&authType=NAME_SEARCH&authToken=hUBG&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A3680614%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907386771%2Ctas%3Aandrea%20go",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAMyAAAAJDI1MWU4OWU4LTZmNTAtNGFmMS1iYzcxLTA5Y2IwYzIyMWIxYQ.jpg"
},
{
"camper": "David McGill",
"quote": "Even if you have a CS degree like I do, you still need projects to prove to employers that you care about coding. Free Code Camp provided me with a platform for doing this. It's all laid out for you - you just have step up and step into the map!",
"github": "dmcgill50",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAEBy74BHsJCpgrbohr2dJxbdXuvMuJDx6k&authType=NAME_SEARCH&authToken=9k8t&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A16894910%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444637012056%2Ctas%3ADavid%20McGill",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAANdAAAAJGE4YWI5NjFiLTQ5MzUtNGQwNC04YThiLWYxMTI4NWM3YmFlMQ.jpg"
},
{
"camper": "Qing Huang",
"quote": "Free Code Camp gives me more confidence at work. Code doesnt look as foreign anymore.",
"github": "qingillustrates",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAOjjjoBDaPY1dtpvngnr8ednNTran6KA3s&authType=NAME_SEARCH&authToken=4zvM&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A61050426%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907310565%2Ctas%3Aqing",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAKsAAAAJDVlNmNkMzUwLWFjNzAtNDQ4OS05NWI5LWYyYmYzOWQzZjRlOQ.jpg"
},
{
"camper": "John Ellis",
"quote": "Free Code Camp has been one of the major contributors to my career in software development. I started as an apps analyst, spent 3 months going through the coursework in my off time and weekends, and just landed a job as a business systems developer.",
"github": "johnmellis",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAbrISEBqAVYOBfhni9mB3YoFFzzrAbYvvo&authType=NAME_SEARCH&authToken=jurJ&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A116072737%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907670143%2Ctas%3Ajohn%20ellis",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/5/000/268/01a/0492529.jpg"
},
{
"camper": "Jonathan Lucas",
"quote": "Free Code Camp has been nothing but supportive and helpful, taking me from a rather basic knowledge of front end technologies to a better, more complete understanding from a full stack perspective.",
"github": "jonslucas",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAATn9H4BI7BP7MBpZ0NR1EvldkWTvAdGy2w&authType=NAME_SEARCH&authToken=hLmG&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A82310270%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635490853%2Ctas%3AJon%20Lucas",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAIcAAAAJGMxMjY3MmEwLTM0ODgtNGU3OS1hZjFiLTJjZjNhMDM3YTUyZQ.jpg"
},
{
"camper": "Alex Dixon",
"quote": "I was hired by the owner of the company, a programmer with 25 years of experience in web development. I graduated from university with a degree in English and had no programming experience prior to attending FreeCodeCamp.",
"github": "alex-dixon",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABhCmLMBLAR1AXskaJXDMT-uLPZ8M7TynPQ&authType=NAME_SEARCH&authToken=k8uX&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A407017651%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444633871133%2Ctas%3Aalex%20dixon",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAMcAAAAJGZhM2Y2ZTU5LWNjODAtNDM5My1hYjAzLTYyYjFlOTcwZjVmZg.jpg"
},
{
"camper": "Ryan Lindeman",
"quote": "Free Code Camp has been great in giving me a direct path to the full stack development skills I wanted to become more involved in projects at work.",
"github": "fai1whale",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAkMT1EBFCY849rMWYSDIEj6kosBJSH9n2s&authType=NAME_SEARCH&authToken=acmj&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A151801681%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907181695%2Ctas%3Aryan%20lind",
"image": "https://media.licdn.com/media/p/4/000/145/24d/18e8af8.jpg"
},
{
"camper": "Stephanie Brown",
"quote": "Free Code Camp has given me structure and a direction while learning to code.",
"github": "strawmitch",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAARqP5cBDDdBxPUzluctvjUhOP3UsiowRtM&authType=NAME_SEARCH&authToken=TDfV&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A74071959%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907473116%2Ctas%3Astephanie%20brown",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAALJAAAAJGI5ZWY1MmNjLTJhMTUtNGI2NS04YTExLTFiOGZlYTRiMTNiOA.jpg"
},
{
"camper": "Jimson Sulit",
"quote": "Aside from the fact that Im learning full stack web development, Free Code Camp has also given me the opportunity to lead local community projects.",
"github": "webdevjedi25",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAWqUccBopX2Wo_P1gYgy0iIEqChwXPTh2k&authType=NAME_SEARCH&authToken=kd5y&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A95048135%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907446780%2Ctas%3Ajimson",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAPzAAAAJDYyOGMxYmEyLTY1NTQtNDE3NS1iMmVkLWUwM2M4NjJiZWFhZg.jpg"
},
{
"camper": "Brian Emory",
"quote": "I like to learn by doing but with the books, while very informative, there was more reading than doing. I came across Free Code Camp which has allowed me to learn by doing. Whereas before I was struggling to learn, I am now not only learning but learning while building cool projects.",
"github": "thebrianemory",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABc3jXwB-iZdZKZIVAvL93RHGB7_J9gDbVA&authType=NAME_SEARCH&authToken=w1Km&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A389516668%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907166795%2Ctas%3Abrian%20emory",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAJOAAAAJDgyZWFhYWFjLTNhZGYtNGQzOC04M2JjLWE1Nzk1NmRiMDY4MA.jpg"
},
{
"camper": "Brian Barrow",
"quote": "Free Code Camp has given me confidence that I can become a web developer.",
"github": "briancbarrow",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAVH-osBCI8WZTtv3Om5WjeD2rYnjQ6z7zA&authType=NAME_SEARCH&authToken=-yWK&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A88603275%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907213309%2Ctas%3Abrian%20barr",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/5/005/07e/272/050fd0e.jpg"
},
{
"camper": "Ralph Cachero",
"quote": "I am a software QA engineer. Free Code Camp has helped me understand what the developers go through.",
"github": "rcachero",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAJEF88BiUtMoxS3Ww7ooI9QmTZdrgP272Q&authType=NAME_SEARCH&authToken=2tza&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A38016975%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907225816%2Ctas%3Aralph",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/1/000/09f/2eb/0ec94ae.jpg"
},
{
"camper": "Ina Tsetsova",
"quote": "Bonfires really make me think and combine programming concepts creatively.",
"github": "Tsetsova",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAjPoIcBJsAF91dqwgxFQ4qct88yFcljXNU&authType=NAME_SEARCH&authToken=l8zY&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A147824775%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907239742%2Ctas%3Aina%20",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/4/005/0ad/379/050ce9d.jpg"
},
{
"camper": "Adam Goswick",
"quote": "Free Code Camp is helping me learn web development when I cant afford to go back to school.",
"github": "thegoz85",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAObbhkBzeCKrzuEB0ssE_iGrBX0Xnu9URc&authType=NAME_SEARCH&authToken=xKaK&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A60517913%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907256670%2Ctas%3Aadam%20g",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/1/005/08d/084/0eeb904.jpg"
},
{
"camper": "Josh Cronkhite",
"quote": "My resume has been bolstered by adding a completely new stack, providing value to my clients and opening up the pool of potential clients that I would have otherwise referred to peers.",
"github": "joshcronkhite",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAGTPvoBg__9rivrYrYgo8sDJ561JpAfhHk&authType=NAME_SEARCH&authToken=6X77&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A26427130%2CauthType%3ANAME_SEARCH%2Cidx%3A1-3-3%2CtarId%3A1441907269831%2Ctas%3Ajosh",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/7/000/276/003/191e9f3.jpg"
},
{
"camper": "Ryan Jones",
"quote": "Learning to code with Free Code Camp has given me a leg up in my career. It has helped to train my brain to think with the logic that computers use. This is a tremendous aid in the field of digital forensics.",
"github": "ryanmjones",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABPJt1MBxC4Yero3PJPhF9rrr_Y7WfOGcCU&authType=NAME_SEARCH&authToken=Dre1&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A331986771%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907281816%2Ctas%3Aryan%20jones",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAbSAAAAJDUwY2RiZTUxLTg1YTktNDQ2Yy05YTZlLTU2NmY2YThlMmY0Yw.jpg"
},
{
"camper": "Kristin Anthony",
"quote": "The layout, pacing, and resources of Free Code Camp have given me focus and shown me a path to mastery. Just being able to tell people in my field that Im learning full stack JavaScript and having projects to show for it has been immensely helpful both with my current position and in my job search.",
"github": "anthkris",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAZRM5MBACvQe36s4cvpe5ZHWEfgxprDUFg&authType=NAME_SEARCH&authToken=pozh&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A105984915%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907298390%2Ctas%3Akristin%20",
"image": "https://media.licdn.com/media/p/4/005/0b3/377/381a362.jpg"
},
{
"camper": "Jimmy Epperson",
"quote": "I learned to build websites, which is now a new service I offer to local businesses.",
"github": "jimmyepp",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAADg3N8BTBm_D58gu8Tgq6UPa3OQ_19CrSE&authType=NAME_SEARCH&authToken=W7Eg&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A14736607%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907323386%2Ctas%3Ajimmy%20epper",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAALWAAAAJDUwZDc5YzYwLTc2MjYtNDIzYy1iYzAyLWNlNzZmMTNjM2M1NA.jpg"
},
{
"camper": "Sara Powell",
"quote": "Ive progressed from not coding very much at all, to coding well enough to land job interviews for front end development positions.",
"github": "newtcobell",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAy1jmQBRjoGSUWd6Zib7FtekpSMBVHr7Vw&authType=NAME_SEARCH&authToken=wpT6&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A213225060%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907337130%2Ctas%3Asara%20powell",
"image": "https://media.licdn.com/media/p/8/000/1be/159/281c5b8.jpg"
},
{
"camper": "John Bull",
"quote": "I am now able to add customized branding and layouts to web applications that fellow employees and customers use everyday. Im now looking to move away from desktop support and into development roles.",
"github": "Jbull328",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABAyfz8BsjE-oGv1k3URGzhRyeupnTGuK3I&authType=NAME_SEARCH&authToken=bnIc&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A271744831%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907350044%2Ctas%3Ajohn%20bull",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAL8AAAAJDliMGU0MTk0LWQ3YTUtNDY0NS1hMTg1LTdhN2Q1NTBlMzA5MQ.jpg"
},
{
"camper": "Rhonadale Florentino",
"quote": "I can now confidently tell clients that I can design their website.",
"github": "None Given",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAI53oUBmy6MPKp1UeHxBy3_y0cyTS4bWow&authType=NAME_SEARCH&authToken=gz62&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A37346949%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907434768%2Ctas%3Arhona",
"image": "https://media.licdn.com/media/p/7/005/0aa/319/1aaa08f.jpg"
},
{
"camper": "Justin Clay Lane",
"quote": "Free Code Camp provided a structured learning experience more akin to an actual class, compared to other free learning sites. I was recently hired to update and maintain the website for a local doctors office. The extra money and experience from that is wonderful.",
"github": "jclane",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAYZYQ4BBY337OqRUhMnZqDJNX1wNXjT7Bk&authType=NAME_SEARCH&authToken=8TbF&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A102326542%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907405129%2Ctas%3Ajustin%20lane",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAI5AAAAJDNmNzViYzdmLTdkMTEtNDllYS1iNTRmLWVmZjgzZTY3ZWNjNQ.jpg"
},
{
"camper": "Angshuman Gupta",
"quote": "Im a co-founder of a startup. We had been coding with PHP, but always wanted to shift to meteor.js. Free Code Camp gave me a structured JavaScript guide.",
"github": "codingang",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAhIipMB6vAXaratEs0MtUd3GgyYm70cvbE&authType=NAME_SEARCH&authToken=pbTj&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A138971795%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907423626%2Ctas%3Aangsh",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAAKPAAAAJGRjMmQwZjY5LTViMmUtNDQyZS04Y2Y3LTRhYjZiYWJlZDQzNw.jpg"
},
{
"camper": "Nick Galluzzo",
"quote": "I currently work in a support role for a tech startup (www.knackhq.com). The more I learn about JavaScript, the more Im able to contribute to a product I really believe in!",
"github": "ngalluzzo",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAjQl1EBZPrbUQ6zGPXmKIuNzpCyqqsnox4&authType=NAME_SEARCH&authToken=9w-G&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A147887953%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907461071%2Ctas%3Anick%20gall",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAANtAAAAJDE3YWZmYjE0LTg4ODYtNDg1Mi1hZDhjLThkZmZhMjkxYWI3Mg.jpg"
},
{
"camper": "Genavieve Clausen",
"quote": "Free Code Camp has benefitted me in numerous ways, including the opportunity to learn in a self-paced, supportive environment. I am excited to be a part of a growing community making lasting connections for the career and lifestyle I am pursuing.",
"github": "GenavieveMarie",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAOISlMBAi43m1SG-xM_S2B8Vy05yiQz5rE&authType=NAME_SEARCH&authToken=AY6E&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A59263571%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907488270%2Ctas%3Agenav",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAWUAAAAJDc2ODU4MjVkLTlmMDUtNDM4My05OTY2LTliMTQxNzFlZmY0OQ.jpg"
},
{
"camper": "Nicholas Slaven",
"quote": "Free Code Camp has given me the courage to open the door to the idea of programming for a career.",
"github": "nslaven22",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA5HGyIBmpNcXY_tfHBkWxXI6OtwsFAeHRQ&authType=NAME_SEARCH&authToken=IIqr&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A239541026%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907370759%2Ctas%3Aslaven",
"image": "https://media.licdn.com/media/p/3/000/222/0d1/2606078.jpg"
},
{
"camper": "Tim Stauffer",
"quote": "I found Free Code Camp more helpful than my MS degree, so I quit college. Learning so much. Also saving $50,000.",
"github": "timstauffer",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAADVcVIBz8UCNjQKl2GUy9ka8UGnQXAXAYw&authType=NAME_SEARCH&authToken=7Hkg&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A13988178%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907522559%2Ctas%3Astauffer",
"image": "https://avatars1.githubusercontent.com/u/3429096?v=3&s=460"
},
{
"camper": "Marquina M Iliev-Piselli",
"quote": "Im re-designing a site for my full-time job.",
"github": "Marquina",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAACYvVUBTuu8dNRHthN1TFiyk137PLDqnv4&authType=NAME_SEARCH&authToken=V_iG&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A10009941%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907639677%2Ctas%3Amarquin",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAZLAAAAJDQ5Nzg4MjJmLWUyMjQtNDI5Ny05NmY5LTE5Yjc1Y2Q1YWFhOA.jpg"
},
{
"camper": "Pete Considine",
"quote": "The guided and structured lessons have been really helpful, as has the relatively slow pace that new concepts are introduced. I had been taking a Udemy course and it really seemed to be skimming the surface of JavaScript in the interest of \"getting to everything.\"",
"github": "Pjconsidine",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAAi8-8BxUVpoi_VuJQmeGWN5zhMBgbvPbs&authType=NAME_SEARCH&authToken=WCEU&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A2290671%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907557932%2Ctas%3Apete%20c",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/3/005/06c/3b2/0ab8c08.jpg"
},
{
"camper": "Khatra Ahmed",
"quote": "I can learn to code with support by my side. Everyone is so helpful and it makes learning to code less of a struggle.",
"github": "Mystfreak",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAbdUsIBApacWEmL7CIxe2q7aevMn7aQvmQ&authType=NAME_SEARCH&authToken=a_zs&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A115167938%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907569985%2Ctas%3Akhatra",
"image": "https://avatars0.githubusercontent.com/u/11299138?v=3&s=460"
},
{
"camper": "Marcus Lyons",
"quote": "Free Code Camp has helped me gain the confidence to automate part of my work responsibilities. I was able to use skills I learned from Free Code Camp to help with writing a bash script to search through mobile app database log files to find errors.",
"github": "auron1223",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA_1aLABo1pVJH9ijSqz8PvLgpzVYkIsjVc&authType=NAME_SEARCH&authToken=cNE6&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A267741360%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441925486836%2Ctas%3Alyons",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAM9AAAAJDA4YjM1NGIxLThjZWYtNDllMi04N2NkLWMzMzk1YWI1MTYyMg.jpg"
},
{
"camper": "Reynald Emmanuel Endaya",
"quote": "There is an active community (even in Manila) and its interactive, unlike all the MOOCs I tried before where I had to listen to somebody speak for a long time. I am learning a lot here and I have not yet lost my momentum.",
"github": "None Given",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAUlm8oBQuXm_Y89_LDC9mb2vOjjQH_pZDo&authType=NAME_SEARCH&authToken=4WJf&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A86350794%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907601893%2Ctas%3Areynald",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/2/000/1a7/0ab/089b5aa.jpg"
},
{
"camper": "Victoria Kariolic",
"quote": "I discovered a coding partner through the Free Code Camp groups who has been able to cover gaps for my client work.",
"github": "Niaskywalk",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAEFmXMBlTFIR2j1G-vJhAMsUOPONILGrLM&authType=NAME_SEARCH&authToken=yGV-&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A17144179%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907613265%2Ctas%3Avictoria%20",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/8/005/025/299/0d297ae.jpg"
},
{
"camper": "Cameron Eshgh",
"quote": "Free Code Camp enables me as a digital marketer to dive right into whatever asset or content and fix things that havent been working, as well as roll up my sleeves when our web developers are not available.",
"github": "eshghitude",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAVdU1MBFFiei4ZYNImnVDcR3H_EiuS6qLY&authType=NAME_SEARCH&authToken=TlgU&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A90002259%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907626390%2Ctas%3Acameron%20",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/6/005/0a4/178/079a07b.jpg"
},
{
"camper": "Devarsh Ruparelia",
"quote": "Even though I am still just a high school student. The startup I intern for said that if I finish the full track of Free Code Camp, they will strongly consider me for their programming jobs. Thanks Free Code Camp!",
"github": "devarsh1997",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAApxpP8BZBcHQzr6Ci3xmkkZX-OSH_oLuJs&authType=NAME_SEARCH&authToken=wdjb&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A175219967%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907682493%2Ctas%3Adevarsh",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/7/005/087/339/14535ee.jpg"
},
{
"camper": "Miranda Bashore",
"quote": "I want to be able to freelance and create dynamic websites. Free Code Camp makes that more of a reality for me, as I cannot afford an expensive bootcamp while getting my Masters degree.",
"github": "DutchBay",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA8KmJMBTtvvgJzjeAUo_YOssh2yLZZlvlk&authType=NAME_SEARCH&authToken=fWay&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A252352659%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907584953%2Ctas%3Amiranda",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/5/005/078/187/0ca3604.jpg"
},
{
"camper": "Christian Morera",
"quote": "Free Code Camp has been a great experience. Ive learned so many things. I am in the process of transitioning from content developer to full stack developer.",
"github": "chrmorfeus",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAMc-tYBtYri0H1KHz1WNQjWxZ23jg0tMNU&authType=NAME_SEARCH&authToken=NzUg&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A52230870%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907694834%2Ctas%3Achristian",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAa-AAAAJDVkYmQyNTdmLTJkM2UtNDRjNi04NjZkLThlMmE3ZTg0NzhlZQ.jpg"
},
{
"camper": "James Allen",
"quote": "I finally feel like I can learn to code in my own time and progress to the point of employability.",
"github": "None Given",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA4OrsIB5WyfuqeECSQO7HYisImVMDiFBl0&authType=NAME_SEARCH&authToken=Uxjm&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A235843266%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907723968%2Ctas%3Ajames%20allen",
"image": "https://media.licdn.com/media/p/5/000/228/30b/1bb1c6f.jpg"
},
{
"camper": "Jason Arnold",
"quote": "I like self-paced learning, so Free Code Camp has been great. The challenges are difficult enough to push boundaries but not so tough to scare people off.",
"github": "thejasonfile",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAABlImsBwAEZ3u3A5NIlCegho8WZ2j4h0w0&authType=NAME_SEARCH&authToken=gaxA&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A6627947%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907738051%2Ctas%3Ajason%20arn",
"image": "https://media.licdn.com/media/p/6/005/05d/271/0bdaef1.jpg"
},
{
"camper": "Kaveet Laxmidas",
"quote": "Free Code Camp is inspiring me to overhaul some of my old open source projects using more modern approaches and technologies.",
"github": "kaveet",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABZooOgBZJg_0MAJ09pd5vROk83oBFA1cEE&authType=NAME_SEARCH&authToken=52Ju&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A375955688%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907749550%2Ctas%3Akaveet%20",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAMiAAAAJDlhMGNiYzdjLTNlZmEtNDI3MC04Mzg4LTU4YTBkYjkxYTg5Zg.jpg"
},
{
"camper": "Brett Guillory",
"quote": "Free Code Camp has given me a great, goal oriented curriculum to learn exactly what I was looking for. And best of all its 100% free!",
"github": "Kurzninja",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAUMPqMBa6GwMTkA_oHUeqnZzyD95FisjwM&authType=NAME_SEARCH&authToken=-mt1&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A84688547%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907760167%2Ctas%3Abrett",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/5/005/054/0cd/0fee17b.jpg"
},
{
"camper": "Kory J. Campbell",
"quote": "I just graduated university, so my financial status is pretty meager, however this camp has definitely helped me improve my skills.",
"github": "@koryjcampbell [sic]",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAtxvTgB0N_uJhW-87Dew4wHyeqLUP-XyZk&authType=NAME_SEARCH&authToken=0hqw&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A192003384%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907770739%2Ctas%3Akory",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/4/000/17a/3cd/3b781f4.jpg"
},
{
"camper": "Bryon Christopher Miller",
"quote": "Free Code Camp has given me a free, online opportunity to study full stack JavaScript in a structured, community-based format. I am very grateful for this opportunity.",
"github": "bryonmiller",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABEXhHoBxj3Uiq7I0a5v1pVkeJ1gWycbm90&authType=NAME_SEARCH&authToken=4klF&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A286753914%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907784405%2Ctas%3Abryon",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/7/005/07d/040/1d3ca82.jpg"
},
{
"camper": "Darren Joy",
"quote": "Great learning opportunity. Good coding challenges and Im meeting some very motivated people.",
"github": "Darrenfj",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAARv6UIBWeXw4ZfCJ70kBKgnhcv8XgnVsa8&authType=NAME_SEARCH&authToken=fMvj&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A74443074%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907795737%2Ctas%3Adarren",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAANwAAAAJGRiNjA5Zjg4LTE0OTEtNGVlNi1hZjdlLWFkOWZhNzk2YzJiNg.jpg"
},
{
"camper": "Stephen Mayeux",
"quote": "Free Code Camp is helpful because its not 100% hand-holding, and it pushes me out of my comfort zone.",
"github": "stephenmayeux",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAjTe7cBhjovoz6zTE_M6MwZ_rr3szhiSOM&authType=NAME_SEARCH&authToken=s6xI&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A148077495%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907806830%2Ctas%3Astephen",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAUmAAAAJDg3MzIzMGVlLWYzZGEtNGE0Yi05ODkzLTFkODkyOWI5N2NjYg.jpg"
},
{
"camper": "John Hillegass",
"quote": "Free Code Camp has given me the confidence that I need when heading into high level client meetings and developer scrum sessions.",
"github": "Ohillio",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAWEO3AB51y8eR2tYF8nydQb8kANkdPwR5U&authType=NAME_SEARCH&authToken=Pzvi&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A92552048%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907818081%2Ctas%3Ajohn%20hille",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/2/000/1cd/27b/2ab4573.jpg"
},
{
"camper": "Eric Hartline",
"quote": "The community is very helpful, and I have already accomplished so much more than what I did with other self-guided courses.",
"github": "wildlifehexagon",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAFitUwByB_tgxdExntMnakgQnTK1H3eEd8&authType=NAME_SEARCH&authToken=230A&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A23246156%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907829391%2Ctas%3Aeric%20har",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/2/000/1e1/095/12800b6.jpg"
},
{
"camper": "Danielle J Moss",
"quote": "Aside from learning to code in a fun way, I also know Im not alone and have somewhere to go when I do get stuck and need help.",
"github": "psykobilliethekid",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAV4ccABlbMXZ5VfzvlYentPOIKzFbjgbZM&authType=NAME_SEARCH&authToken=D-EU&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A91779520%2CauthType%3ANAME_SEARCH%2Cidx%3A1-4-4%2CtarId%3A1441907855210%2Ctas%3Adanielle%20",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/5/000/1be/2cb/16e5e39.jpg"
},
{
"camper": "Orcun Tonyali",
"quote": "The thorough curriculum helped a lot in managing my companys website.",
"github": "orcuntonyali",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAVwBQIBvE3-M8pDWxzep9umHDnV6JjKmTU&authType=NAME_SEARCH&authToken=h4NM&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A91227394%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907869032%2Ctas%3Aorcun",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAI7AAAAJDE2ZGVkY2IxLTkyZDEtNDUwNS1iNmU0LWI5ZWUzYjUxZDIyMw.jpg"
},
{
"camper": "Brendan Murphy",
"quote": "I like that it isnt just a 9 week course. The chat room and partner coding were also very helpful.",
"github": "dendari",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAA06V8BqPNnPod-FGRuvifILht-QwZX3YY&authType=NAME_SEARCH&authToken=9SFh&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A3467615%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907882775%2Ctas%3Abrendan%20m",
"image": "https://media.licdn.com/media/p/5/000/2be/073/198504b.jpg"
},
{
"camper": "Michael Berry",
"quote": "Free Code Camp has helped me learn JavaScript, jQuery, and Bootstrap as well as helped me brush up on my HTML and CSS skills. I was laid off from Boeing in April. Im hoping to land a job as a JavaScript developer as I get closer to finishing the curriculum. I wish I had known about Free Code Camp sooner.",
"github": "Karnblack ",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAGRqf4BwCI3cdJw9wAPc6NlReG3fzOIQq0&authType=NAME_SEARCH&authToken=SqNG&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A26323454%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907895359%2Ctas%3Amichael%20berr",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAM3AAAAJDc2YTRmMjY1LTcxNjQtNDJjOC1hYWJmLTJkMGFkMWVhYjE3Mw.jpg"
},
{
"camper": "Angie Canon",
"quote": "Free Code Camp is helping my career. I work with developers and Im beginning to understand their world better. I can phrase questions more clearly, and begin to guess what an issue might be related to.",
"github": "angiecan",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAACfWbABAMsll9ovljvvsLpH317o47hNHX0&authType=NAME_SEARCH&authToken=UmUf&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A10443184%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907913670%2Ctas%3Aangie%20canon",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/8/000/20b/098/273de00.jpg"
},
{
"camper": "Irfan Kucuk",
"quote": "Ive long been looking for a place that could keep me interested in learning how to code. Ive tried several Codecademy and comparable places, but none have proven as engaging as Free Code Camp.",
"github": "Ikucuk",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAA5ripkBiFAjXkB3ndO6sKiiq6gD21mk6bw&authType=NAME_SEARCH&authToken=46t_&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A241928857%2CauthType%3ANAME_SEARCH%2Cidx%3A1-2-2%2CtarId%3A1441907929553%2Ctas%3Airfan%20kuc",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/4/005/027/3f1/08ce9a4.jpg"
},
{
"camper": "Jonathan Kvicky",
"quote": "Free Code Camp has given me a strong foundational advantage into pursuing a career in software/web development, and has also served as a great platform for connecting with others who share the same passion for software engineering.",
"github": "jonkvix",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABk3i9YB_hcw1AyVg2QHaf8KMQ8ADQ_R_vg&authType=NAME_SEARCH&authToken=0yLa&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A423070678%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907942441%2Ctas%3Ajonathan%20kv",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAANTAAAAJDk3ZGMwMjFlLTZkNDYtNDgwYy05NGE0LTk5ZjgwNGQ4NWU0OA.jpg"
},
{
"camper": "Susannah Skyer Gupta",
"quote": "As a jack-of-all-trades at a small educational software company, Im already putting my coding skills to work, beginning to submit my own pull requests for bug fixes instead of just opening a problem ticket and waiting for someone else to fix it.",
"github": "SuzGupta",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAFIosEBLewkmbuudMwAqiTM5YE3wHvcE4A&authType=NAME_SEARCH&authToken=dFye&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A21537473%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907953988%2Ctas%3Asusanna",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/7/005/025/20f/3d29475.jpg"
},
{
"camper": "Puneet Shivanand",
"quote": "Free Code Camp has helped me create and maintain a website for a local bioinformatics conference.",
"github": "puneet-shivanand",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAArBgXABw4qoSJQoGjqrvU6_vBX1gUmcwGg&authType=NAME_SEARCH&authToken=bARS&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A180453744%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907966038%2Ctas%3Apuneet",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAUYAAAAJGI3NmNlMGNhLWM1NDEtNGNlNS1iNmQzLTY0OTM3OGEzMTk0Yg.jpg"
},
{
"camper": "Ian Seabrook",
"quote": "Ive made connections with people I never would have approached before Free Code Camp.",
"github": "ianseabrook",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAuVUi4BSJ3K6fcyTa2fnZr_9Oosb3nKM34&authType=NAME_SEARCH&authToken=b7uD&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A194335278%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907982480%2Ctas%3Aian%20seabroo",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAJNAAAAJDVkMmI1MDYxLTc1ZmEtNDY0Yy05MTRhLTY1ZjVkNWQyNWI1Ng.jpg"
},
{
"camper": "Oleh Kuchuk",
"quote": "The coding exercises helped me to prepare for my first job interview.",
"github": "drkraken",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAABgy6MwBva2OKpsffAU-OBBeTC7qahTYpGw&authType=NAME_SEARCH&authToken=Xm_u&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A405989580%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441907996469%2Ctas%3Aoleh%20kuchuk",
"image": "https://pbs.twimg.com/profile_images/518155039781580800/djkuOlrL.jpeg"
},
{
"camper": "Larisa Bekerman",
"quote": "Free Code Camp has made me more comfortable with certain aspects of code and helped me review and understand concepts in a more hands-on style. Some people learn by reading theory, I dont understand things until Ive made them work myself!",
"github": "xaosqueen",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAB-SHUBga96BB-iaHe7QFI-S2dFmeUQaq0&authType=NAME_SEARCH&authToken=CWOo&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A8276085%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441908013366%2Ctas%3Alarisa%20beker",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/8/005/093/243/2c06287.jpg"
},
{
"camper": "Jesse Mull",
"quote": "I learned more using Free Code Camp in three months than I ever could have at a traditional university.",
"github": "jessemull",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAr2HfcBswHtmQeLM1rxDEg7GdCuxvNin5s&authType=NAME_SEARCH&authToken=nca0&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A183901687%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441908026733%2Ctas%3Ajesse%20mull",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/3/005/016/3ff/006213a.jpg"
},
{
"camper": "Mihai Popescu",
"quote": "The exercises helped me hone my skills and get an internship at a tech startup. My projects were a great talking point in the interview, showing them what I did and how I approached the problems. Great thing you are doing here.",
"github": "Mihaisavezi",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAApQxGQBYz-WAQu_0zXPTkW-R7QbdaXEZeA&authType=NAME_SEARCH&authToken=r84S&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A173065316%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441908038920%2Ctas%3Amihai%20p",
"image": "https://lh6.googleusercontent.com/-4JB6FPzm9ZE/VakUEj7WYsI/AAAAAAAALkU/4C0ILUwn-B8/w888-h891-no/profilepic.png"
},
{
"camper": "Normandy Real",
"quote": "I'm doing Free Code Camp to transition from mainframe programming to front end development.",
"github": "mandyreal",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAdebIIBHfcSRnxGI-j6g5y6crfOXSg55Dc&authType=NAME_SEARCH&authToken=xLNy&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A123628674%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444636619442%2Ctas%3ANormandy%20Real",
"image": "https://media.licdn.com/media/AAEAAQAAAAAAAAMrAAAAJDAxMmE0ZWI1LWU0MjctNDRjYS1hNjdkLTYwZTI5NjUxMDhjYw.jpg"
},
{
"camper": "Zlatko Cabric",
"quote": "I am still in school, pursuing an AS in web development. The JavaScript course in college was a breeze thanks to Free Code Camp.",
"github": "zlajac ",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAsCCFMBUlE24Ie41G_YS3XhdtQMDl5vCZA&authType=NAME_SEARCH&authToken=h1m7&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A184682579%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441908055072%2Ctas%3Azlat",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAALQAAAAJDMzNjY4M2UwLWVlYWEtNGQwYS04MDY0LTVjNGVhNGNhYWM5OQ.jpg"
},
{
"camper": "Travis Wouters",
"quote": "Free Code Camp helped me add skillsets to my resume that show experience instead of knowledge without practical application.",
"github": "",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAABHP0YBddxsmaf2OghV2jAy17RVMhig4RM&authType=NAME_SEARCH&authToken=a7pC&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A4669254%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444634846844%2Ctas%3ATravis%20Wouters",
"image": "https://media.licdn.com/media/p/8/005/07d/2f1/1792a44.jpg"
},
{
"camper": "Geoff Storbeck",
"quote": "I've been able to build tools that has helped moved my current career further and has opened up many more doors in the field.",
"github": "storbeck",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAdVQZYBHPYLt5efKwqZmiDM5SqIdH0_AR4&authType=NAME_SEARCH&authToken=EDd-&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A123027862%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1444635255807%2Ctas%3AGeoff%20Storbeck%09",
"image": "https://media.licdn.com/media/p/1/000/124/306/339eee6.jpg"
},
{
"camper": "Anthony DePaolo",
"quote": "I can learn web development at my own pace, which is great with my crazy lifes schedule. It also doesnt cost $10k-$17k, which I just cant fork over right now.",
"github": "adepaolo",
"linkedin": "https://www.linkedin.com/profile/view?id=AAkAAAOCUkABzCvw3p1mBiPbbFWq91BEFXGXKxA&authType=NAME_SEARCH&authToken=7zb7&locale=en_US&trk=tyah&trkInfo=clickedVertical%3Amynetwork%2CclickedEntityId%3A58872384%2CauthType%3ANAME_SEARCH%2Cidx%3A1-1-1%2CtarId%3A1441908068309%2Ctas%3Aanthony%20depa",
"image": "https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAAJPAAAAJGI4NGY3ZGI1LWM2N2UtNGQ2Ni1iZDUwLTFkN2I4YWM2YThjMQ.jpg"
}
]

View File

@ -2,7 +2,8 @@ require('dotenv').load();
var pmx = require('pmx');
pmx.init();
var uuid = require('node-uuid'),
var _ = require('lodash'),
uuid = require('node-uuid'),
assign = require('lodash').assign,
loopback = require('loopback'),
boot = require('loopback-boot'),
@ -16,6 +17,7 @@ var getUsernameFromProvider = require('./utils/auth').getUsernameFromProvider;
var generateKey =
require('loopback-component-passport/lib/models/utils').generateKey;
var isBeta = !!process.env.BETA;
var app = loopback();
expressState.extend(app);
@ -92,16 +94,19 @@ Object.keys(passportProviders).map(function(strategy) {
);
});
app.start = function() {
app.start = _.once(function() {
app.listen(app.get('port'), function() {
app.emit('started');
console.log(
'FreeCodeCamp server listening on port %d in %s mode',
'FreeCodeCamp server listening on port %d in %s',
app.get('port'),
app.get('env')
);
if (isBeta) {
console.log('Free Code Camp is in beta mode');
}
});
});
};
module.exports = app;

View File

@ -2,8 +2,12 @@ export default function getJobServices(app) {
const { Job } = app.models;
return {
name: 'job',
name: 'jobs',
read: (req, resource, params, config, cb) => {
const id = params ? params.id : null;
if (id) {
return Job.findById(id, cb);
}
Job.find({}, (err, jobs) => {
cb(err, jobs);
});

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